PATH
[1] "/Users/mmkhan/Documents/Research/pml/pml_wo_infl/pml_github"

Microbiome Analysis

Microbiome analysis of oral PMLs and cancer from total trx sequencing. Pathoscope was used to filter, align and map the reads to several organisms including bacterial, viral and fungi.

load host eset

Load eset

cpm_eset$Class
 [1] 1-Control   3-Dysplasia 3-Dysplasia 3-Dysplasia 4-OSCC      3-Dysplasia 2-HkNR      1-Control   2-HkNR      2-HkNR      2-HkNR      1-Control  
[13] 1-Control   1-Control   3-Dysplasia 1-Control   3-Dysplasia 2-HkNR      2-HkNR      2-HkNR      2-HkNR      3-Dysplasia 2-HkNR      4-OSCC     
[25] 2-HkNR      2-HkNR      4-OSCC      4-OSCC      2-HkNR      3-Dysplasia 3-Dysplasia 3-Dysplasia 4-OSCC      1-Control   2-HkNR      3-Dysplasia
[37] 2-HkNR      4-OSCC      3-Dysplasia 2-HkNR      3-Dysplasia 3-Dysplasia 3-Dysplasia 1-Control   3-Dysplasia 1-Control   1-Control   3-Dysplasia
[49] 1-Control   1-Control   4-OSCC      1-Control   4-OSCC      3-Dysplasia 3-Dysplasia 3-Dysplasia 3-Dysplasia 4-OSCC      3-Dysplasia 1-Control  
[61] 1-Control   1-Control   1-Control   2-HkNR      1-Control   2-HkNR     
Levels: 1-Control 2-HkNR 3-Dysplasia 4-OSCC

load animalcules MAE

New animalcules file w/o infl

File created from the shiny app with run_animalcules() easy-to-upload .tsv files from pathoscope.

MAE <- readRDS(file.path(PATH, "data/animalcules_data_2022-03-14.rds"))

colData(MAE[['MicrobeGenetics']]) <- cbind(colData(MAE[['MicrobeGenetics']]), "Sample_ID"=rownames(colData(MAE[['MicrobeGenetics']])))
    
#add smoking and progression status to colData
colData(MAE[['MicrobeGenetics']]) <- cbind(colData(MAE[['MicrobeGenetics']]), pData(cpm_eset)[match(MAE[['MicrobeGenetics']]$Sample_ID, gsub(cpm_eset$Sample_ID, pattern = "_", replacement = "-")), c('Smoking_status', 'imputed_smoking_label', 'Progression_status')])
    
MAE[['MicrobeGenetics']]$Progression_status <- ifelse(is.na(MAE[['MicrobeGenetics']]$Progression_status) | (MAE[['MicrobeGenetics']]$Progression_status =="Stable"), MAE[['MicrobeGenetics']]$Class, MAE[['MicrobeGenetics']]$Progression_status)

MAE[['MicrobeGenetics']]$Class <- recode(MAE[['MicrobeGenetics']]$Class, "4-Cancer"="4-OSCC")
saveRDS(MAE, file.path(PATH, "data/2023_06_19_animalcules_data.rds"))

Wrappers

## creating a relabu barplots wrapper to rotate the axix but didn't work
relabu_wrapper <- function (MAE, tax_level, order_organisms = c(), sort_by = c("nosort", 
  "conditions", "organisms", "alphabetically"), group_samples = FALSE, 
  group_conditions = "ALL", sample_conditions = c(), isolate_samples = c(), 
  discard_samples = c(), show_legend = TRUE) 
{
  sort_by <- match.arg(sort_by)
  MAE <- mae_pick_samples(MAE, isolate_samples, discard_samples)
  microbe <- MAE[["MicrobeGenetics"]]
  tax_table <- as.data.frame(rowData(microbe))
  sam_table <- as.data.frame(colData(microbe))
  counts_table <- as.data.frame(assays(microbe))[, rownames(sam_table)]
  sam_table %<>% df_char_to_factor()
  relabu_table <- counts_table %>% upsample_counts(tax_table, 
    tax_level) %>% counts_to_relabu() %>% base::t() %>% 
    base::as.data.frame()
  if (group_samples & !is.null(group_conditions)) {
    if (group_conditions == "ALL") {
      relabu_table$covariate <- rep("ALL", nrow(relabu_table))
    }
    else {
      relabu_table$covariate <- sam_table[[group_conditions]]
    }
    relabu_table <- relabu_table %>% reshape2::melt(id.vars = "covariate") %>% 
      S4Vectors::aggregate(. ~ variable + covariate, ., 
        mean) %>% reshape2::dcast(formula = covariate ~ 
      variable) %>% magrittr::set_rownames(.[["covariate"]]) %>% 
      dplyr::select(-one_of(c("covariate")))
    sam_table <- rownames(relabu_table) %>% as.data.frame() %>% 
      magrittr::set_colnames(c(group_conditions)) %>% 
      magrittr::set_rownames(rownames(relabu_table))
  }
  relabu_table <- relabu_table[, order(colSums(relabu_table)), 
    drop = FALSE]
  if (!is.null(order_organisms)) {
    org_order <- c(setdiff(colnames(relabu_table), order_organisms), 
      rev(order_organisms))
    relabu_table <- relabu_table[, org_order]
  }
  if (sort_by == "alphabetically") {
    org_order <- sort(colnames(relabu_table), decreasing = TRUE)
    relabu_table <- relabu_table[, org_order]
  }
  if (sort_by == "organisms") {
    for (i in seq_len(ncol(relabu_table))) {
      relabu_table <- relabu_table[order(relabu_table[, 
        i]), ]
    }
  }
  if (!is.null(sample_conditions) || (group_samples && group_conditions != 
    "ALL")) {
    if (!group_samples) {
      sam_table <- sam_table[, sample_conditions, drop = FALSE]
    }
    if (sort_by == "conditions") {
      for (i in ncol(sam_table):1) {
        sam_table <- sam_table[order(sam_table[[i]]), 
          , drop = FALSE]
      }
      relabu_table <- relabu_table[order(match(rownames(relabu_table), 
        rownames(sam_table))), , drop = FALSE]
    }
    else {
      sam_table <- sam_table[order(match(rownames(sam_table), 
        rownames(relabu_table))), , drop = FALSE]
    }
    if (nrow(sam_table) > 1) {
      hover.txt <- c()
      for (i in seq_len(ncol(sam_table))) {
        hover.txt <- cbind(hover.txt, as.character(sam_table[[i]]))
      }
      mat <- sam_table %>% data.matrix() %>% apply(2, 
        function(x) (x - min(x))/(max(x) - min(x)))
      hm <- plotly::plot_ly(x = colnames(mat), y = rownames(mat), 
        z = mat, type = "heatmap", showscale = FALSE,
        hoverinfo = "x+y+text", text = hover.txt) %>% 
        layout(xaxis = list(title = "", tickangle = -45), 
          yaxis = list(showticklabels = FALSE, type = "category", 
            ticks = ""))
    }
  }
  relabu_table$samples <- rownames(relabu_table)
  sbp <- plotly::plot_ly(relabu_table, y = ~samples, x = relabu_table[[colnames(relabu_table)[1]]], 
    type = "bar", textposition = "outside", orientaton="h",
    name = substr(colnames(relabu_table)[1], 1, 40)) %>% 
    layout(font = list(size = 10), xaxis = list(title = "Relative Abundance", 
      automargin = TRUE), yaxis = list(title = "", type = "category", 
      tickmode = "array", tickvals = rownames(relabu_table), 
      showticklabels = FALSE, categoryorder = "trace", 
      automargin = TRUE), barmode = "stack", showlegend = show_legend)
  for (i in 2:(ncol(relabu_table) - 1)) {
    sbp <- add_trace(sbp, x = relabu_table[[colnames(relabu_table)[i]]], 
      name = substr(colnames(relabu_table)[i], 1, 40))
  }
  if (exists("hm") && nrow(sam_table) > 1) {
    hm_sbp <- subplot(hm, sbp, widths = c(0.1, 0.9))
    hm_sbp$elementId <- NULL
    return(hm_sbp)
  }
  else {
    sbp$elementId <- NULL
    return(sbp)
  }
}


relabu_boxplot_wrapper <- function (MAE, tax_level, condition, organisms = c(), datatype = c("counts", 
  "relative abundance", "logcpm")) 
{
  datatype <- match.arg(datatype)
  microbe <- MAE[["MicrobeGenetics"]]
  tax_table <- as.data.frame(rowData(microbe))
  sam_table <- as.data.frame(colData(microbe))
  counts_table <- as.data.frame(assays(microbe))[, rownames(sam_table)]
  sam_table %<>% df_char_to_factor()
  df <- counts_table %>% upsample_counts(tax_table, tax_level) %>% 
    {
      if (datatype == "relative abundance") {
        animalcules::counts_to_relabu(.)
      }
      else if (datatype == "logcpm") {
        animalcules::counts_to_logcpm(.)
      }
      else {
        .
      }
    } %>% .[organisms, , drop = FALSE] %>% t() %>% as.data.frame() %>% 
    merge(sam_table[, condition, drop = FALSE], by = 0, 
      all = TRUE) %>% reshape2::melt(by = organisms, variable.name = "organisms")
  
   g <- ggplot2::ggplot(df, 
                       ggplot2::aes(x = organisms, y = value, color = Class, fill = Class)) + 
    geom_boxplot() + 
    viridis::scale_color_viridis(alpha = 0.90, discrete=T)+
    viridis::scale_fill_viridis(alpha = 0.90, discrete =T)+
    #ggplot2::geom_jitter(size=0.2) +
    theme_bw() + labs(y = "log-CPM")+
    ggpubr::stat_compare_means(method = "anova", label = 'p.format')+
     
    ggplot2::theme(axis.text.x = element_text(angle = 45, hjust = 1)) 
  return(g)
}

Diversity plots

condition
[1] "Class"
suppressPackageStartupMessages(library(plotly))

animalcules::alpha_div_boxplot(MAE = MAE, tax_level = "genus", condition = "Class", alpha_metric = "shannon")
animalcules::alpha_div_boxplot(MAE = MAE, tax_level = "species", condition = "Class", alpha_metric = "shannon")

animalcules::diversity_beta_heatmap(MAE = MAE, tax_level = "genus", input_beta_method = "bray",input_bdhm_select_conditions =   "Class", input_bdhm_sort_by = "conditions")
animalcules::diversity_beta_heatmap(MAE = MAE, tax_level = "species", input_beta_method = "bray",input_bdhm_select_conditions =   "Class", input_bdhm_sort_by = "conditions")

Rel abu of MoI

r1 <- relabu_boxplot_wrapper(MAE = MAE, tax_level = "genus", condition = "Class", organisms = c("Fusobacterium", "Neisseria", "Prevotella", "Shewanella", "Streptococcus", "Candida"), datatype = "logcpm")
Using Row.names, Class as id variables
r1
ggsave(plot = r1, filename = file.path("../pml_microbiome_wo_infl/rel_abu_can_assoc_gen.png"),width = 4, height = 4, dpi = 300)

Diff. Exp

diffanal <- differential_abundance(MAE,
                            tax_level="genus",
                            input_da_condition=c("Class"),
                            input_da_condition_covariate = c("Sex", "imputed_smoking_label"),
                            min_num_filter  = 500,
                            input_da_padj_cutoff = 0.05, method = 'DESeq2')
DT::datatable(diffanal)
#write.xlsx(diffanal, file=file.path(PATH, "06_30_diffanal_microbes.xlsx"))

#get microbes unique to each contrast-condition
#up in first group and down in the other - up reg
microbe_list <- list("ctrl.vs.hknr_up"=diffanal$microbe[which(diffanal$Contrast=='1-Control vs. 2-HkNR' & diffanal$padj <=0.05 & diffanal$log2FoldChange > 1)],
     "ctrl.vs.hknr_down"=diffanal$microbe[which(diffanal$Contrast=='1-Control vs. 2-HkNR' & diffanal$padj <=0.05 & diffanal$log2FoldChange < -1)],
      "ctrl.vs.dys_up"=diffanal$microbe[which(diffanal$Contrast=='1-Control vs. 3-Dysplasia' & diffanal$padj <=0.05 & diffanal$log2FoldChange > 1)],
     "ctrl.vs.dys_down"=diffanal$microbe[which(diffanal$Contrast=='1-Control vs. 3-Dysplasia' & diffanal$padj <=0.05 & diffanal$log2FoldChange < -1)],
     "ctrl.vs.cancer_up"=diffanal$microbe[which(diffanal$Contrast=='1-Control vs. 4-Cancer' & diffanal$padj <=0.05 & diffanal$log2FoldChange > 1)],
     "ctrl.vs.cancer_down"=diffanal$microbe[which(diffanal$Contrast=='1-Control vs. 4-Cancer' & diffanal$padj <=0.05 & diffanal$log2FoldChange < -1)])
microbe_list

#saveRDS(microbe_list, file.path("results/06_30_microbe_diffex_list.RDS"))

MSEA

Microbe set enrichment analysis (MSEA) Load results from msea - ran on scc with a jupyter notebook

OSCC vs. Ctrl

msea_cancer_up <- read.csv(file.path(PATH, "results/msea_cancer_ctrl_up.csv"))
msea_cancer_dn <- read.csv(file.path(PATH, "results/msea_cancer_ctrl_dn.csv"))
msea_pml_up <- read.csv(file.path(PATH, "results/msea_pml_ctrl_up.csv"))
msea_pml_dn <- read.csv(file.path(PATH, "results/msea_pml_ctrl_dn.csv"))

msea_cancer_up <- msea_cancer_up[msea_cancer_up$qvalue<=0.05 & msea_cancer_up$combined_score > 0,]
msea_cancer_dn <- msea_cancer_dn[msea_cancer_dn$qvalue<=0.05,]#none significant
msea_pml_up <- msea_pml_up[msea_pml_up$qvalue<=0.05 & msea_pml_up$combined_score > 0, ]
msea_pml_dn <- msea_pml_dn[msea_pml_dn$qvalue<=0.05,]#none significant

msea_genes <- list("cancer" = msea_cancer_up$term, 
                   "pml"=msea_pml_up$term)

HALLMARK <-  msigdb_gsets("Homo sapiens", "H", "")
names(HALLMARK$genesets) <- names(HALLMARK$genesets) %>% strsplit( "HALLMARK_" ) %>% sapply( tail, 1 )

REACTOME <- msigdb_gsets(species="Homo sapiens", category="C2", subcategory="CP:REACTOME", clean = TRUE)
names(REACTOME$genesets) <- names(REACTOME$genesets) %>% strsplit( "REACTOME_" ) %>% sapply( tail, 1 )


hyp_mic1 <- hypeR(signature = msea_genes, genesets = HALLMARK, background = 1300)
hyp_mic2 <- hypeR(signature = msea_genes, genesets = HALLMARK)
hyp_dots(hyp_mic1, merge = T, fdr = 0.1, title = "Hallmark(bck=1300)")
hyp_mic1$as.list()
hyp_dots(hyp_mic2, merge = T, fdr = 0.1, title = "Hallmark(bck=all)")
hyp_mic2$as.list()

hyp_mic3 <- hypeR(signature = msea_genes, genesets = REACTOME, background = 1300)
hyp_mic4 <- hypeR(signature = msea_genes, genesets = REACTOME)
hyp_dots(hyp_mic3, merge = T, fdr = 0.1, title = "Reactome(bck=1300)")
hyp_mic3$as.list()
hyp_dots(hyp_mic4, merge = T, fdr = 0.1, title = "Reactome(bck=all)")
hyp_mic4$as.list()

Cancer genes

diffanal_res <- xlsx::read.xlsx(file.path(PATH, "results/pml_diffex_wo_infl/PML.DiffEx.results.Can.vs.Ctrl.xlsx"), sheetIndex = 1)
diffanal_res <- diffanal_res[diffanal_res$padj<=0.05,]
diff_cancer <- diffanal_res[diffanal_res$gene %in% msea_genes$cancer, ]

ggplot(data = diff_cancer, aes(x=gene, y = log2FoldChange),)+
  geom_bar(aes( fill=log2FoldChange>0), stat = "identity")+ 
  theme_bw()+  
  ggplot2::theme(axis.text.x = element_text(angle = 45, hjust = 1))+
  scale_fill_manual(guide = "none", breaks = c(TRUE, FALSE), values=c("blue4", "red"))

Cancer vs Ctrl up

library(tidyverse)
msea_cancer_up_new<- separate_rows(msea_cancer_up, shared, sep = ",", convert = T)
msea_cancer_up_new$shared <- gsub(msea_cancer_up_new$shared, pattern = "\\[", replacement = "")
msea_cancer_up_new$shared <- gsub(msea_cancer_up_new$shared, pattern = "\\]", replacement = "")
msea_cancer_up_new$shared <- gsub(msea_cancer_up_new$shared, pattern = "\\'", replacement = "")
msea_cancer_up_new$shared <- gsub(msea_cancer_up_new$shared, pattern = " ", replacement = "")
msea_cancer_up_new

igraph

  • Choose genes that come up diff analysis
  • to adjust for degree size for genes double it
tiff(file.path(PATH, "results/06_16_cancer_microbes_ig.png"),units="in", width=8, height=8, res=600)
plot(g, 
     vertex.color = adjustcolor(colrs,  alpha.f = 1), 
     vertex.frame.color = colrs,
     layout = LO, 
     vertex.size = ifelse(V(g)$name %in% unquote(msea_cancer_up_de$term), deg*2.5, deg*1.95),
     #vertex.size = deg*3,
    vertex.label.dist = ifelse(V(g)$name %in% unquote(msea_cancer_up_de$term), -8, 13),
    vertex.label.degree =  ifelse(V(g)$name %in% unquote(msea_cancer_up_de$term), 3.14, -3.14), # The position of the label in relation to the vertex, where 0 is right, “pi” is left, “pi/2” is below, and “-pi/2” is above
     #vertex.label.cex=0.5,
    vertex.label.cex= ifelse(V(g)$name %in% unquote(msea_cancer_up_de$term), 1, 1),
     vertex.frame.width=0.1,
     vertex.label.color="black",
     edge.width=abs(E(g)$weight)/20, 
     vertex.label.family="Arial",
    vertex.label.font=ifelse(V(g)$name %in% unquote(msea_cancer_up_de$term),1,3),
     edge.color = "black",
     asp = 2.5)
dev.off()
null device 
          1 
msea_cancer_up_de <- msea_cancer_up_new[msea_cancer_up_new$term %in% diff_cancer$gene, ]
df <- msea_cancer_up_de[, c("term", "shared", "combined_score")]
transformed_mat <- xtabs(combined_score~., df)
attr(transformed_mat, "class") <- NULL #ignore this

g <- graph.incidence(transformed_mat, weighted = TRUE)
is.bipartite(g)
deg <- degree(g, mode="all")
#colrs <- c("#FFD580","#6CA6CD")[V(g)$type + 1L]

colrs <- c("#6CA6CD", "red")[V(g)$type + 1L]
colrs <- ifelse(colrs=="red" & V(g)$name %in% c("CEACAM1", "GALE", "IL18"), "blue", colrs)

V(g)$shape <- ifelse(V(g)$name %in% unquote(msea_cancer_up_de$term), "circle", "square")

LO = matrix(0, nrow=vcount(g), ncol=2)
LO[!V(g)$type, 2] = 1

LO[V(g)$type, 1]  = rank(V(g)$name[V(g)$type]) - 1
LO[!V(g)$type, 1] = (rank(V(g)$name[!V(g)$type]) - 1) * 
    (sum(V(g)$type) - 1)  /  (sum(!V(g)$type) - 1)

#for a vertical bipartite graph
LO <- LO[,2:1]

tiff(file.path(PATH, "results/06_16_cancer_microbes_ig.png"),units="in", width=5, height=5, res=600)
plot(g, 
     vertex.color = adjustcolor(colrs,  alpha.f = 1), 
     vertex.frame.color = colrs,
     layout = LO, 
     vertex.size = ifelse(V(g)$name %in% unquote(msea_cancer_up_de$term), deg*2.5, deg*1.95),
     #vertex.size = deg*3,
     vertex.label.dist = -1,
     vertex.label.cex=0.3,
     vertex.frame.width=0.1,
     vertex.label.color="black",
     edge.width=abs(E(g)$weight)/20, 
     vertex.label.family="Arial",
     vertex.label.font=4,
     vertex.label.face = 
     edge.color = "black",
     #edge.color=ifelse(E(g)$weight > 0, "red","blue"),
     asp = 2.5)
dev.off()
microbes_cancer_shared <- unique(msea_cancer_up_de$shared)
DT::datatable(msea_cancer_up_de)

PML vs. Ctrl

diffanal_res_hknr <- xlsx::read.xlsx(file.path(PATH, "results/pml_diffex_wo_infl/PML.DiffEx.results.Hknr.vs.Ctrl.xlsx"), sheetIndex = 1)
diffanal_res_dys <- xlsx::read.xlsx(file.path(PATH, "results/pml_diffex_wo_infl/PML.DiffEx.results.Dys.vs.Ctrl.xlsx"), sheetIndex = 1)

diffanal_res_hknr$gene <- diffanal_res_hknr$NA.
diffanal_res_dys$gene <- diffanal_res_dys$NA.

diffanal_pml <- rbind(diffanal_res_dys, diffanal_res_hknr)

diffanal_pml <- diffanal_pml[diffanal_pml$padj<=0.05,]
diff_pml<- diffanal_pml[diffanal_pml$gene %in% msea_genes$pml, ]

ggplot(data = diff_pml, aes(x=gene, y = log2FoldChange),)+
  geom_bar(aes( fill=log2FoldChange>0), stat = "identity")+ 
  theme_bw()+  
  ggplot2::theme(axis.text.x = element_text(angle = 45, hjust = 1))+
  scale_fill_manual(guide = "none", breaks = c(TRUE, FALSE), values=c("blue4", "red"))

PML vs Ctrl up

msea_pml_up_new<- separate_rows(msea_pml_up, shared, sep = ",", convert = T)
msea_pml_up_new$shared <- gsub(msea_pml_up_new$shared, pattern = "\\[", replacement = "")
msea_pml_up_new$shared <- gsub(msea_pml_up_new$shared, pattern = "\\]", replacement = "")
msea_pml_up_new$shared <- gsub(msea_pml_up_new$shared, pattern = "\\'", replacement = "")
msea_pml_up_new$shared <- gsub(msea_pml_up_new$shared, pattern = " ", replacement = "")
msea_pml_up_new
  • Choose genes that come up diff analysis
  • to adjust for degree size for genes double it
msea_pml_up_de <- msea_pml_up_new[msea_pml_up_new$term %in% diff_pml$gene, ]
df <- msea_pml_up_de[, c("shared", "term", "combined_score")]
transformed_mat <- xtabs(combined_score~., df)
attr(transformed_mat, "class") <- NULL #ignore this

g <- graph.incidence(transformed_mat, weighted = TRUE)
is.bipartite(g)
deg <- degree(g, mode="all")

colrs <- c("#7EC384", "#FFD580")[V(g)$type + 1L]

V(g)$shape <- ifelse(V(g)$name %in% unquote(msea_pml_up_de$term), "circle", "square")
#V(g)$label.cez <- 1

LO = matrix(0, nrow=vcount(g), ncol=2)
LO[!V(g)$type, 2] = 1

LO[V(g)$type, 1]  = rank(V(g)$name[V(g)$type]) - 1
LO[!V(g)$type, 1] = (rank(V(g)$name[!V(g)$type]) - 1) * (sum(V(g)$type) - 1)  /  (sum(!V(g)$type) - 1)

#for a vertical bipartite graph
LO <- LO[,2:1]
#LO[,2] <- LO[,2]*2

plot(g, 
     vertex.color = adjustcolor(colrs,  alpha.f = .6), 
     vertex.frame.color = colrs,
     layout = LO, 
     vertex.size = ifelse(V(g)$name %in% unquote(msea_pml_up_de$term), deg*1.25, deg*1.25),
     vertex.label.dist = ifelse(V(g)$name %in% unquote(msea_pml_up_de$term), 0, 0),
     vertex.label.cex= ifelse(V(g)$name %in% unquote(msea_pml_up_de$term), 0.18, 0.35),
     vertex.frame.width=0.1,
     vertex.label.font=3,
     edge.width=abs(E(g)$weight)/200, 
     vertex.label.family="Arial",
     edge.color=ifelse(E(g)$weight > 0, "red", "blue"),  asp = 3)
tiff(file.path(PATH, "results/06_16_pml_microbes_ig.png"),units="in", width=8, height=8, res=600)
plot(g, 
     vertex.color = adjustcolor(colrs,  alpha.f = 1), 
     vertex.frame.color = colrs,
     layout = LO, 
    vertex.size = ifelse(V(g)$name %in% unquote(msea_pml_up_de$term), deg*1.75, deg*1.25),
     vertex.label.cex= ifelse(V(g)$name %in% unquote(msea_pml_up_de$term), 1,1),
    vertex.label.dist = ifelse(V(g)$name %in% unquote(msea_pml_up_de$term), 7.5, -12.5),
    vertex.label.degree =  ifelse(V(g)$name %in% unquote(msea_pml_up_de$term), -3.14,-3.14), # The position of the label in relation to the vertex, where 0 is right, “pi” is left, “pi/2” is below, and “-pi/2” is above
     #vertex.label.cex=0.5,
     vertex.frame.width=0.1,
     vertex.label.color="black",
     edge.width=abs(E(g)$weight)/30, 
     vertex.label.family="Arial",
     vertex.label.font=ifelse(V(g)$name %in% unquote(msea_pml_up_de$term), 1,3),
     edge.color = "black",
     asp = 3)
dev.off()
null device 
          1 
LS0tCnRpdGxlOiAiUE1MIE1pY3JvYmlvbWUgQW5hbHlzaXMiCmF1dGhvcjogIk0uIE11emFtaWwgS2hhbiIKZGF0ZTogIjA2LzIzLzIwMjIiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgICB0aGVtZTogZmxhdGx5CiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB0cnVlCiAgaHRtbF9ub3RlYm9vazoKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgdGhlbWU6IGZsYXRseQogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogdHJ1ZQogIHBkZl9kb2N1bWVudDoKICAgIHRvYzogeWVzCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKa25pdHI6Om9wdHNfa25pdCRzZXQocm9vdC5kaXIgPSAiL1VzZXJzL21ta2hhbi9Eb2N1bWVudHMvUmVzZWFyY2gvcG1sL3BtbF93b19pbmZsL3BtbF9naXRodWIiKQpgYGAKCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9Rn0KbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHN0cmluZ3IpCmxpYnJhcnkoRFQpCmxpYnJhcnkocGx5cikKbGlicmFyeShkcGx5cikKbGlicmFyeShiaW9tYVJ0KQpsaWJyYXJ5KEJpb2Jhc2UpCmxpYnJhcnkocmVzaGFwZTIpCmxpYnJhcnkoZm9ybWF0dGFibGUpCmxpYnJhcnkoVmVubkRpYWdyYW0pCmxpYnJhcnkoaHlwZVIpCmxpYnJhcnkoeGxzeCkKbGlicmFyeShhbmltYWxjdWxlcykKbGlicmFyeShtYWdyaXR0cikKbGlicmFyeShTdW1tYXJpemVkRXhwZXJpbWVudCkKbGlicmFyeShnZ3NjaSkKbGlicmFyeShlcGx5KQpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeShpZ3JhcGgpClBBVEggPC0gZ2V0d2QoKQpgYGAKCiMgTWljcm9iaW9tZSBBbmFseXNpcyAKCk1pY3JvYmlvbWUgYW5hbHlzaXMgb2Ygb3JhbCBQTUxzIGFuZCBjYW5jZXIgZnJvbSB0b3RhbCB0cnggc2VxdWVuY2luZy4gUGF0aG9zY29wZSB3YXMgdXNlZCB0byBmaWx0ZXIsIGFsaWduIGFuZCBtYXAgdGhlIHJlYWRzIHRvIHNldmVyYWwgb3JnYW5pc21zIGluY2x1ZGluZyBiYWN0ZXJpYWwsIHZpcmFsIGFuZCBmdW5naS4KCiMjIGxvYWQgaG9zdCBlc2V0IHsudGFic2V0IC50YWJzZXQtZmFkZSAudGFic2V0LXBpbGxzfQoKTG9hZCBlc2V0CgpgYGB7cn0KZXNldCA8LSByZWFkUkRTKGZpbGUucGF0aChQQVRILCAiZGF0YS8yMDIxXzA4XzIwX2VzZXRfaW1wdXRlZF91cGRhdGVkLlJEUyIpKQplU2V0X3dvX2luZmwgPC0gZXNldAp0YWJsZShlU2V0X3dvX2luZmwkQ2xhc3MpCgplU2V0X3dvX2luZmwkQ2xhc3MgPC0gcmVjb2RlKGVTZXRfd29faW5mbCRDbGFzcywgIkNhbmNlciI9Ik9TQ0MiKQplU2V0X3dvX2luZmwkQ2xhc3MgPC0gZmFjdG9yKGVTZXRfd29faW5mbCRDbGFzcywgbGV2ZWxzID0gYygiQ29udHJvbCIsICJIa05SIiwgIkR5c3BsYXNpYSIsICJPU0NDIikpCgpjcG1fZXNldCA8LSBlU2V0X3dvX2luZmwKZXhwcnMoY3BtX2VzZXQpIDwtIGFwcGx5KGV4cHJzKGNwbV9lc2V0KSwgMiwgZnVuY3Rpb24oeCkge3gvKHN1bSh4KS8xMDAwMDAwKX0pCnByaW50KGRpbShjcG1fZXNldCkpCgpjcG1fZXNldCRDbGFzcyA8LSByZWNvZGUoY3BtX2VzZXQkQ2xhc3MsICJDb250cm9sIj0iMS1Db250cm9sIiwgIkhrTlIiPSIyLUhrTlIiLCAiRHlzcGxhc2lhIj0iMy1EeXNwbGFzaWEiLCAiT1NDQyI9IjQtT1NDQyIpCmNwbV9lc2V0JENsYXNzIDwtIGZhY3RvcihjcG1fZXNldCRDbGFzcywgbGV2ZWxzID0gYygiMS1Db250cm9sIiwgIjItSGtOUiIsICIzLUR5c3BsYXNpYSIsICI0LU9TQ0MiKSkKYGBgCgoKIyMgbG9hZCBhbmltYWxjdWxlcyBNQUUgey50YWJzZXQgLnRhYnNldC1mYWRlIC50YWJzZXQtcGlsbHN9Ck5ldyBhbmltYWxjdWxlcyBmaWxlIHcvbyBpbmZsCgpGaWxlIGNyZWF0ZWQgZnJvbSB0aGUgc2hpbnkgYXBwIHdpdGggcnVuX2FuaW1hbGN1bGVzKCkgZWFzeS10by11cGxvYWQgLnRzdiBmaWxlcyBmcm9tIHBhdGhvc2NvcGUuIAoKYGBge3Igd2FybmluZz1GfQpNQUUgPC0gcmVhZFJEUyhmaWxlLnBhdGgoUEFUSCwgImRhdGEvYW5pbWFsY3VsZXNfZGF0YV8yMDIyLTAzLTE0LnJkcyIpKQoKY29sRGF0YShNQUVbWydNaWNyb2JlR2VuZXRpY3MnXV0pIDwtIGNiaW5kKGNvbERhdGEoTUFFW1snTWljcm9iZUdlbmV0aWNzJ11dKSwgIlNhbXBsZV9JRCI9cm93bmFtZXMoY29sRGF0YShNQUVbWydNaWNyb2JlR2VuZXRpY3MnXV0pKSkKICAgIAojYWRkIHNtb2tpbmcgYW5kIHByb2dyZXNzaW9uIHN0YXR1cyB0byBjb2xEYXRhCmNvbERhdGEoTUFFW1snTWljcm9iZUdlbmV0aWNzJ11dKSA8LSBjYmluZChjb2xEYXRhKE1BRVtbJ01pY3JvYmVHZW5ldGljcyddXSksIHBEYXRhKGNwbV9lc2V0KVttYXRjaChNQUVbWydNaWNyb2JlR2VuZXRpY3MnXV0kU2FtcGxlX0lELCBnc3ViKGNwbV9lc2V0JFNhbXBsZV9JRCwgcGF0dGVybiA9ICJfIiwgcmVwbGFjZW1lbnQgPSAiLSIpKSwgYygnU21va2luZ19zdGF0dXMnLCAnaW1wdXRlZF9zbW9raW5nX2xhYmVsJywgJ1Byb2dyZXNzaW9uX3N0YXR1cycpXSkKICAgIApNQUVbWydNaWNyb2JlR2VuZXRpY3MnXV0kUHJvZ3Jlc3Npb25fc3RhdHVzIDwtIGlmZWxzZShpcy5uYShNQUVbWydNaWNyb2JlR2VuZXRpY3MnXV0kUHJvZ3Jlc3Npb25fc3RhdHVzKSB8IChNQUVbWydNaWNyb2JlR2VuZXRpY3MnXV0kUHJvZ3Jlc3Npb25fc3RhdHVzID09IlN0YWJsZSIpLCBNQUVbWydNaWNyb2JlR2VuZXRpY3MnXV0kQ2xhc3MsIE1BRVtbJ01pY3JvYmVHZW5ldGljcyddXSRQcm9ncmVzc2lvbl9zdGF0dXMpCgpNQUVbWydNaWNyb2JlR2VuZXRpY3MnXV0kQ2xhc3MgPC0gcmVjb2RlKE1BRVtbJ01pY3JvYmVHZW5ldGljcyddXSRDbGFzcywgIjQtQ2FuY2VyIj0iNC1PU0NDIikKc2F2ZVJEUyhNQUUsIGZpbGUucGF0aChQQVRILCAiZGF0YS8yMDIzXzA2XzE5X2FuaW1hbGN1bGVzX2RhdGEucmRzIikpCmBgYAoKYGBge3J9Ck1BRSA8LSByZWFkUkRTKGZpbGUucGF0aChQQVRILCAiZGF0YS8yMDIzXzA2XzE5X2FuaW1hbGN1bGVzX2RhdGEucmRzIikpCnAxIDwtIGFuaW1hbGN1bGVzOjpyZWxhYnVfYmFycGxvdChNQUUsCiAgICAgICAgICAgICAgICAgICAgdGF4X2xldmVsPSJwaHlsdW0iLAogICAgICAgICAgICAgICAgICAgIHNvcnRfYnk9ICJjb25kaXRpb25zIiwKICAgICAgICAgICAgICAgICAgICBzYW1wbGVfY29uZGl0aW9ucz1jKCdDbGFzcycpLAogICAgICAgICAgICAgICAgICAgIHNob3dfbGVnZW5kPVRSVUUpCnAxICAgICAgICAgICAgICAgICAKCnAyIDwtIGFuaW1hbGN1bGVzOjpyZWxhYnVfYmFycGxvdChNQUUsCiAgICAgICAgICAgICAgICAgICAgdGF4X2xldmVsPSJnZW51cyIsCiAgICAgICAgICAgICAgICAgICAgc29ydF9ieT0gImNvbmRpdGlvbnMiLAogICAgICAgICAgICAgICAgICAgIHNhbXBsZV9jb25kaXRpb25zPWMoJ0NsYXNzJyksCiAgICAgICAgICAgICAgICAgICAgc2hvd19sZWdlbmQ9VFJVRSkKcDIKCnAzIDwtIGFuaW1hbGN1bGVzOjpyZWxhYnVfYmFycGxvdChNQUUsCiAgICAgICAgICAgICAgICAgICAgdGF4X2xldmVsPSJzcGVjaWVzIiwKICAgICAgICAgICAgICAgICAgICBzb3J0X2J5PSAiY29uZGl0aW9ucyIsCiAgICAgICAgICAgICAgICAgICAgc2FtcGxlX2NvbmRpdGlvbnM9YygnQ2xhc3MnKSwKICAgICAgICAgICAgICAgICAgICBzaG93X2xlZ2VuZD1UUlVFKQpwMwoKcDIgPC0gYW5pbWFsY3VsZXM6OnJlbGFidV9iYXJwbG90KE1BRSwKICAgICAgICAgICAgICAgICAgICB0YXhfbGV2ZWw9ImdlbnVzIixvcmRlcl9vcmdhbmlzbXMgPSBjKCJGdXNvYmFjdGVyaXVtIiwgIlN0cmVwdG9jb2NjdXMiKSwKICAgICAgICAgICAgICAgICAgICBzb3J0X2J5PSAiY29uZGl0aW9ucyIsCiAgICAgICAgICAgICAgICAgICAgc2FtcGxlX2NvbmRpdGlvbnM9cmV2KGMoJ0NsYXNzJykpLAogICAgICAgICAgICAgICAgICAgIHNob3dfbGVnZW5kPVRSVUUsICkKcDIKCmBgYAoKCiMjIFdyYXBwZXJzCgpgYGB7cn0KIyMgY3JlYXRpbmcgYSByZWxhYnUgYmFycGxvdHMgd3JhcHBlciB0byByb3RhdGUgdGhlIGF4aXggYnV0IGRpZG4ndCB3b3JrCnJlbGFidV93cmFwcGVyIDwtIGZ1bmN0aW9uIChNQUUsIHRheF9sZXZlbCwgb3JkZXJfb3JnYW5pc21zID0gYygpLCBzb3J0X2J5ID0gYygibm9zb3J0IiwgCiAgImNvbmRpdGlvbnMiLCAib3JnYW5pc21zIiwgImFscGhhYmV0aWNhbGx5IiksIGdyb3VwX3NhbXBsZXMgPSBGQUxTRSwgCiAgZ3JvdXBfY29uZGl0aW9ucyA9ICJBTEwiLCBzYW1wbGVfY29uZGl0aW9ucyA9IGMoKSwgaXNvbGF0ZV9zYW1wbGVzID0gYygpLCAKICBkaXNjYXJkX3NhbXBsZXMgPSBjKCksIHNob3dfbGVnZW5kID0gVFJVRSkgCnsKICBzb3J0X2J5IDwtIG1hdGNoLmFyZyhzb3J0X2J5KQogIE1BRSA8LSBtYWVfcGlja19zYW1wbGVzKE1BRSwgaXNvbGF0ZV9zYW1wbGVzLCBkaXNjYXJkX3NhbXBsZXMpCiAgbWljcm9iZSA8LSBNQUVbWyJNaWNyb2JlR2VuZXRpY3MiXV0KICB0YXhfdGFibGUgPC0gYXMuZGF0YS5mcmFtZShyb3dEYXRhKG1pY3JvYmUpKQogIHNhbV90YWJsZSA8LSBhcy5kYXRhLmZyYW1lKGNvbERhdGEobWljcm9iZSkpCiAgY291bnRzX3RhYmxlIDwtIGFzLmRhdGEuZnJhbWUoYXNzYXlzKG1pY3JvYmUpKVssIHJvd25hbWVzKHNhbV90YWJsZSldCiAgc2FtX3RhYmxlICU8PiUgZGZfY2hhcl90b19mYWN0b3IoKQogIHJlbGFidV90YWJsZSA8LSBjb3VudHNfdGFibGUgJT4lIHVwc2FtcGxlX2NvdW50cyh0YXhfdGFibGUsIAogICAgdGF4X2xldmVsKSAlPiUgY291bnRzX3RvX3JlbGFidSgpICU+JSBiYXNlOjp0KCkgJT4lIAogICAgYmFzZTo6YXMuZGF0YS5mcmFtZSgpCiAgaWYgKGdyb3VwX3NhbXBsZXMgJiAhaXMubnVsbChncm91cF9jb25kaXRpb25zKSkgewogICAgaWYgKGdyb3VwX2NvbmRpdGlvbnMgPT0gIkFMTCIpIHsKICAgICAgcmVsYWJ1X3RhYmxlJGNvdmFyaWF0ZSA8LSByZXAoIkFMTCIsIG5yb3cocmVsYWJ1X3RhYmxlKSkKICAgIH0KICAgIGVsc2UgewogICAgICByZWxhYnVfdGFibGUkY292YXJpYXRlIDwtIHNhbV90YWJsZVtbZ3JvdXBfY29uZGl0aW9uc11dCiAgICB9CiAgICByZWxhYnVfdGFibGUgPC0gcmVsYWJ1X3RhYmxlICU+JSByZXNoYXBlMjo6bWVsdChpZC52YXJzID0gImNvdmFyaWF0ZSIpICU+JSAKICAgICAgUzRWZWN0b3JzOjphZ2dyZWdhdGUoLiB+IHZhcmlhYmxlICsgY292YXJpYXRlLCAuLCAKICAgICAgICBtZWFuKSAlPiUgcmVzaGFwZTI6OmRjYXN0KGZvcm11bGEgPSBjb3ZhcmlhdGUgfiAKICAgICAgdmFyaWFibGUpICU+JSBtYWdyaXR0cjo6c2V0X3Jvd25hbWVzKC5bWyJjb3ZhcmlhdGUiXV0pICU+JSAKICAgICAgZHBseXI6OnNlbGVjdCgtb25lX29mKGMoImNvdmFyaWF0ZSIpKSkKICAgIHNhbV90YWJsZSA8LSByb3duYW1lcyhyZWxhYnVfdGFibGUpICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIAogICAgICBtYWdyaXR0cjo6c2V0X2NvbG5hbWVzKGMoZ3JvdXBfY29uZGl0aW9ucykpICU+JSAKICAgICAgbWFncml0dHI6OnNldF9yb3duYW1lcyhyb3duYW1lcyhyZWxhYnVfdGFibGUpKQogIH0KICByZWxhYnVfdGFibGUgPC0gcmVsYWJ1X3RhYmxlWywgb3JkZXIoY29sU3VtcyhyZWxhYnVfdGFibGUpKSwgCiAgICBkcm9wID0gRkFMU0VdCiAgaWYgKCFpcy5udWxsKG9yZGVyX29yZ2FuaXNtcykpIHsKICAgIG9yZ19vcmRlciA8LSBjKHNldGRpZmYoY29sbmFtZXMocmVsYWJ1X3RhYmxlKSwgb3JkZXJfb3JnYW5pc21zKSwgCiAgICAgIHJldihvcmRlcl9vcmdhbmlzbXMpKQogICAgcmVsYWJ1X3RhYmxlIDwtIHJlbGFidV90YWJsZVssIG9yZ19vcmRlcl0KICB9CiAgaWYgKHNvcnRfYnkgPT0gImFscGhhYmV0aWNhbGx5IikgewogICAgb3JnX29yZGVyIDwtIHNvcnQoY29sbmFtZXMocmVsYWJ1X3RhYmxlKSwgZGVjcmVhc2luZyA9IFRSVUUpCiAgICByZWxhYnVfdGFibGUgPC0gcmVsYWJ1X3RhYmxlWywgb3JnX29yZGVyXQogIH0KICBpZiAoc29ydF9ieSA9PSAib3JnYW5pc21zIikgewogICAgZm9yIChpIGluIHNlcV9sZW4obmNvbChyZWxhYnVfdGFibGUpKSkgewogICAgICByZWxhYnVfdGFibGUgPC0gcmVsYWJ1X3RhYmxlW29yZGVyKHJlbGFidV90YWJsZVssIAogICAgICAgIGldKSwgXQogICAgfQogIH0KICBpZiAoIWlzLm51bGwoc2FtcGxlX2NvbmRpdGlvbnMpIHx8IChncm91cF9zYW1wbGVzICYmIGdyb3VwX2NvbmRpdGlvbnMgIT0gCiAgICAiQUxMIikpIHsKICAgIGlmICghZ3JvdXBfc2FtcGxlcykgewogICAgICBzYW1fdGFibGUgPC0gc2FtX3RhYmxlWywgc2FtcGxlX2NvbmRpdGlvbnMsIGRyb3AgPSBGQUxTRV0KICAgIH0KICAgIGlmIChzb3J0X2J5ID09ICJjb25kaXRpb25zIikgewogICAgICBmb3IgKGkgaW4gbmNvbChzYW1fdGFibGUpOjEpIHsKICAgICAgICBzYW1fdGFibGUgPC0gc2FtX3RhYmxlW29yZGVyKHNhbV90YWJsZVtbaV1dKSwgCiAgICAgICAgICAsIGRyb3AgPSBGQUxTRV0KICAgICAgfQogICAgICByZWxhYnVfdGFibGUgPC0gcmVsYWJ1X3RhYmxlW29yZGVyKG1hdGNoKHJvd25hbWVzKHJlbGFidV90YWJsZSksIAogICAgICAgIHJvd25hbWVzKHNhbV90YWJsZSkpKSwgLCBkcm9wID0gRkFMU0VdCiAgICB9CiAgICBlbHNlIHsKICAgICAgc2FtX3RhYmxlIDwtIHNhbV90YWJsZVtvcmRlcihtYXRjaChyb3duYW1lcyhzYW1fdGFibGUpLCAKICAgICAgICByb3duYW1lcyhyZWxhYnVfdGFibGUpKSksICwgZHJvcCA9IEZBTFNFXQogICAgfQogICAgaWYgKG5yb3coc2FtX3RhYmxlKSA+IDEpIHsKICAgICAgaG92ZXIudHh0IDwtIGMoKQogICAgICBmb3IgKGkgaW4gc2VxX2xlbihuY29sKHNhbV90YWJsZSkpKSB7CiAgICAgICAgaG92ZXIudHh0IDwtIGNiaW5kKGhvdmVyLnR4dCwgYXMuY2hhcmFjdGVyKHNhbV90YWJsZVtbaV1dKSkKICAgICAgfQogICAgICBtYXQgPC0gc2FtX3RhYmxlICU+JSBkYXRhLm1hdHJpeCgpICU+JSBhcHBseSgyLCAKICAgICAgICBmdW5jdGlvbih4KSAoeCAtIG1pbih4KSkvKG1heCh4KSAtIG1pbih4KSkpCiAgICAgIGhtIDwtIHBsb3RseTo6cGxvdF9seSh4ID0gY29sbmFtZXMobWF0KSwgeSA9IHJvd25hbWVzKG1hdCksIAogICAgICAgIHogPSBtYXQsIHR5cGUgPSAiaGVhdG1hcCIsIHNob3dzY2FsZSA9IEZBTFNFLAogICAgICAgIGhvdmVyaW5mbyA9ICJ4K3krdGV4dCIsIHRleHQgPSBob3Zlci50eHQpICU+JSAKICAgICAgICBsYXlvdXQoeGF4aXMgPSBsaXN0KHRpdGxlID0gIiIsIHRpY2thbmdsZSA9IC00NSksIAogICAgICAgICAgeWF4aXMgPSBsaXN0KHNob3d0aWNrbGFiZWxzID0gRkFMU0UsIHR5cGUgPSAiY2F0ZWdvcnkiLCAKICAgICAgICAgICAgdGlja3MgPSAiIikpCiAgICB9CiAgfQogIHJlbGFidV90YWJsZSRzYW1wbGVzIDwtIHJvd25hbWVzKHJlbGFidV90YWJsZSkKICBzYnAgPC0gcGxvdGx5OjpwbG90X2x5KHJlbGFidV90YWJsZSwgeSA9IH5zYW1wbGVzLCB4ID0gcmVsYWJ1X3RhYmxlW1tjb2xuYW1lcyhyZWxhYnVfdGFibGUpWzFdXV0sIAogICAgdHlwZSA9ICJiYXIiLCB0ZXh0cG9zaXRpb24gPSAib3V0c2lkZSIsIG9yaWVudGF0b249ImgiLAogICAgbmFtZSA9IHN1YnN0cihjb2xuYW1lcyhyZWxhYnVfdGFibGUpWzFdLCAxLCA0MCkpICU+JSAKICAgIGxheW91dChmb250ID0gbGlzdChzaXplID0gMTApLCB4YXhpcyA9IGxpc3QodGl0bGUgPSAiUmVsYXRpdmUgQWJ1bmRhbmNlIiwgCiAgICAgIGF1dG9tYXJnaW4gPSBUUlVFKSwgeWF4aXMgPSBsaXN0KHRpdGxlID0gIiIsIHR5cGUgPSAiY2F0ZWdvcnkiLCAKICAgICAgdGlja21vZGUgPSAiYXJyYXkiLCB0aWNrdmFscyA9IHJvd25hbWVzKHJlbGFidV90YWJsZSksIAogICAgICBzaG93dGlja2xhYmVscyA9IEZBTFNFLCBjYXRlZ29yeW9yZGVyID0gInRyYWNlIiwgCiAgICAgIGF1dG9tYXJnaW4gPSBUUlVFKSwgYmFybW9kZSA9ICJzdGFjayIsIHNob3dsZWdlbmQgPSBzaG93X2xlZ2VuZCkKICBmb3IgKGkgaW4gMjoobmNvbChyZWxhYnVfdGFibGUpIC0gMSkpIHsKICAgIHNicCA8LSBhZGRfdHJhY2Uoc2JwLCB4ID0gcmVsYWJ1X3RhYmxlW1tjb2xuYW1lcyhyZWxhYnVfdGFibGUpW2ldXV0sIAogICAgICBuYW1lID0gc3Vic3RyKGNvbG5hbWVzKHJlbGFidV90YWJsZSlbaV0sIDEsIDQwKSkKICB9CiAgaWYgKGV4aXN0cygiaG0iKSAmJiBucm93KHNhbV90YWJsZSkgPiAxKSB7CiAgICBobV9zYnAgPC0gc3VicGxvdChobSwgc2JwLCB3aWR0aHMgPSBjKDAuMSwgMC45KSkKICAgIGhtX3NicCRlbGVtZW50SWQgPC0gTlVMTAogICAgcmV0dXJuKGhtX3NicCkKICB9CiAgZWxzZSB7CiAgICBzYnAkZWxlbWVudElkIDwtIE5VTEwKICAgIHJldHVybihzYnApCiAgfQp9CgoKcmVsYWJ1X2JveHBsb3Rfd3JhcHBlciA8LSBmdW5jdGlvbiAoTUFFLCB0YXhfbGV2ZWwsIGNvbmRpdGlvbiwgb3JnYW5pc21zID0gYygpLCBkYXRhdHlwZSA9IGMoImNvdW50cyIsIAogICJyZWxhdGl2ZSBhYnVuZGFuY2UiLCAibG9nY3BtIikpIAp7CiAgZGF0YXR5cGUgPC0gbWF0Y2guYXJnKGRhdGF0eXBlKQogIG1pY3JvYmUgPC0gTUFFW1siTWljcm9iZUdlbmV0aWNzIl1dCiAgdGF4X3RhYmxlIDwtIGFzLmRhdGEuZnJhbWUocm93RGF0YShtaWNyb2JlKSkKICBzYW1fdGFibGUgPC0gYXMuZGF0YS5mcmFtZShjb2xEYXRhKG1pY3JvYmUpKQogIGNvdW50c190YWJsZSA8LSBhcy5kYXRhLmZyYW1lKGFzc2F5cyhtaWNyb2JlKSlbLCByb3duYW1lcyhzYW1fdGFibGUpXQogIHNhbV90YWJsZSAlPD4lIGRmX2NoYXJfdG9fZmFjdG9yKCkKICBkZiA8LSBjb3VudHNfdGFibGUgJT4lIHVwc2FtcGxlX2NvdW50cyh0YXhfdGFibGUsIHRheF9sZXZlbCkgJT4lIAogICAgewogICAgICBpZiAoZGF0YXR5cGUgPT0gInJlbGF0aXZlIGFidW5kYW5jZSIpIHsKICAgICAgICBhbmltYWxjdWxlczo6Y291bnRzX3RvX3JlbGFidSguKQogICAgICB9CiAgICAgIGVsc2UgaWYgKGRhdGF0eXBlID09ICJsb2djcG0iKSB7CiAgICAgICAgYW5pbWFsY3VsZXM6OmNvdW50c190b19sb2djcG0oLikKICAgICAgfQogICAgICBlbHNlIHsKICAgICAgICAuCiAgICAgIH0KICAgIH0gJT4lIC5bb3JnYW5pc21zLCAsIGRyb3AgPSBGQUxTRV0gJT4lIHQoKSAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JSAKICAgIG1lcmdlKHNhbV90YWJsZVssIGNvbmRpdGlvbiwgZHJvcCA9IEZBTFNFXSwgYnkgPSAwLCAKICAgICAgYWxsID0gVFJVRSkgJT4lIHJlc2hhcGUyOjptZWx0KGJ5ID0gb3JnYW5pc21zLCB2YXJpYWJsZS5uYW1lID0gIm9yZ2FuaXNtcyIpCiAgCiAgIGcgPC0gZ2dwbG90Mjo6Z2dwbG90KGRmLCAKICAgICAgICAgICAgICAgICAgICAgICBnZ3Bsb3QyOjphZXMoeCA9IG9yZ2FuaXNtcywgeSA9IHZhbHVlLCBjb2xvciA9IENsYXNzLCBmaWxsID0gQ2xhc3MpKSArIAogICAgZ2VvbV9ib3hwbG90KCkgKyAKICAgIHZpcmlkaXM6OnNjYWxlX2NvbG9yX3ZpcmlkaXMoYWxwaGEgPSAwLjkwLCBkaXNjcmV0ZT1UKSsKICAgIHZpcmlkaXM6OnNjYWxlX2ZpbGxfdmlyaWRpcyhhbHBoYSA9IDAuOTAsIGRpc2NyZXRlID1UKSsKICAgICNnZ3Bsb3QyOjpnZW9tX2ppdHRlcihzaXplPTAuMikgKwogICAgdGhlbWVfYncoKSArIGxhYnMoeSA9ICJsb2ctQ1BNIikrCiAgICBnZ3B1YnI6OnN0YXRfY29tcGFyZV9tZWFucyhtZXRob2QgPSAiYW5vdmEiLCBsYWJlbCA9ICdwLmZvcm1hdCcpKwogICAgIAogICAgZ2dwbG90Mjo6dGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgCiAgcmV0dXJuKGcpCn0KCmBgYAoKIyMgRGl2ZXJzaXR5IHBsb3RzCgpgYGB7cn0KYWxwaGFfZGl2ZXJzaXR5X3dyYXBwZXIgPC0gZnVuY3Rpb24gKE1BRSwgdGF4X2xldmVsLCBjb25kaXRpb24sIGFscGhhX21ldHJpYyA9IGMoImludmVyc2Vfc2ltcHNvbiIsIAogICJnaW5pX3NpbXBzb24iLCAic2hhbm5vbiIsICJmaXNoZXIiLCAiY292ZXJhZ2UiLCAidW5pdCIpKSAKewogIG1pY3JvYmUgPC0gTUFFW1siTWljcm9iZUdlbmV0aWNzIl1dCiAgdGF4X3RhYmxlIDwtIGFzLmRhdGEuZnJhbWUoU3VtbWFyaXplZEV4cGVyaW1lbnQ6OnJvd0RhdGEobWljcm9iZSkpCiAgc2FtX3RhYmxlIDwtIGFzLmRhdGEuZnJhbWUoU3VtbWFyaXplZEV4cGVyaW1lbnQ6OmNvbERhdGEobWljcm9iZSkpCiAgY291bnRzX3RhYmxlIDwtIGFzLmRhdGEuZnJhbWUoU3VtbWFyaXplZEV4cGVyaW1lbnQ6OmFzc2F5cyhtaWNyb2JlKSlbLCByb3duYW1lcyhzYW1fdGFibGUpXQogIGNvdW50c190YWJsZSAlPD4lIHVwc2FtcGxlX2NvdW50cyh0YXhfdGFibGUsIHRheF9sZXZlbCkKICBzYW1fdGFibGUkcmljaG5lc3MgPC0gZGl2ZXJzaXRpZXMoY291bnRzX3RhYmxlLCBpbmRleCA9IGFscGhhX21ldHJpYykKICBjb2xuYW1lcyhzYW1fdGFibGUpW25jb2woc2FtX3RhYmxlKV0gPC0gInJpY2huZXNzIgogIGNvbG5hbWVzKHNhbV90YWJsZSlbd2hpY2goY29sbmFtZXMoc2FtX3RhYmxlKSA9PSBjb25kaXRpb24pXSA8LSAiY29uZGl0aW9uIgogIAogIGcgPC0gZ2dwbG90Mjo6Z2dwbG90KHNhbV90YWJsZSwgCiAgICAgICAgICAgICAgICAgICAgICAgZ2dwbG90Mjo6YWVzKGNvbmRpdGlvbiwgcmljaG5lc3MsIGNvbG9yID0gY29uZGl0aW9uLCBmaWxsID0gY29uZGl0aW9uKSkgKyAKICAgIGdlb21fYm94cGxvdCgpICsgCiAgICB2aXJpZGlzOjpzY2FsZV9jb2xvcl92aXJpZGlzKGFscGhhID0gMC45MCwgZGlzY3JldGU9VFJVRSkrCiAgICB2aXJpZGlzOjpzY2FsZV9maWxsX3ZpcmlkaXMoYWxwaGEgPSAwLjkwLCBkaXNjcmV0ZSA9IFRSVUUpKwogICAgZ2dwbG90Mjo6Z2VvbV9qaXR0ZXIoc2l6ZT0wLjMpICsKICAgICNnZ3B1YnI6OnN0YXRfY29tcGFyZV9tZWFucyhtZXRob2QgPSAiYW5vdmEiLCAgbGFiZWwgPSAncC5mb3JtYXQnKSArCiAgICB0aGVtZV9idygpICsKICAgIGdncGxvdDI6OnRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICsKICAgIGdncGxvdDI6OmxhYnModGl0bGUgPSBwYXN0ZSgiQWxwaGEgZGl2ZXJzaXR5IGJldHdlZW4gIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uZGl0aW9uLCAiICgiLCBhbHBoYV9tZXRyaWMsICIpIiwgc2VwID0gIiIpKQogICAgZyA8LSBnICsgbGFicyh5ID0gYWxwaGFfbWV0cmljKQogICAgcmV0dXJuKGcpCn0KCmExIDwtIGFscGhhX2RpdmVyc2l0eV93cmFwcGVyKE1BRSA9IE1BRSwgdGF4X2xldmVsID0gImdlbnVzIiwgY29uZGl0aW9uID0gIkNsYXNzIiwgYWxwaGFfbWV0cmljID0gInNoYW5ub24iKQphMQpgYGAKCgoKYGBge3J9Cm1pY3JvYmUgPC0gTUFFW1siTWljcm9iZUdlbmV0aWNzIl1dCnNhbV90YWJsZSA8LSBhcy5kYXRhLmZyYW1lKFN1bW1hcml6ZWRFeHBlcmltZW50Ojpjb2xEYXRhKG1pY3JvYmUpKQp0YXhfdGFibGUgPC0gYXMuZGF0YS5mcmFtZShTdW1tYXJpemVkRXhwZXJpbWVudDo6cm93RGF0YShtaWNyb2JlKSkKY291bnRzX3RhYmxlIDwtIGFzLmRhdGEuZnJhbWUoU3VtbWFyaXplZEV4cGVyaW1lbnQ6OmFzc2F5cyhtaWNyb2JlKSlbLCByb3duYW1lcyhzYW1fdGFibGUpXQpjb3VudHNfdGFibGUgJTw+JSB1cHNhbXBsZV9jb3VudHModGF4X3RhYmxlLCAiZ2VudXMiKQpzYW1fdGFibGUkcmljaG5lc3MgPC0gZGl2ZXJzaXRpZXMoY291bnRzX3RhYmxlLCBpbmRleCA9ICJzaGFubm9uIikKY29sbmFtZXMoc2FtX3RhYmxlKVtuY29sKHNhbV90YWJsZSldIDwtICJyaWNobmVzcyIKCmNvbmRpdGlvbiA8LSAiQ2xhc3MiCmNvbG5hbWVzKHNhbV90YWJsZSlbd2hpY2goY29sbmFtZXMoc2FtX3RhYmxlKSA9PSBjb25kaXRpb24pXSA8LSAiQ2xhc3MiCiAgCnNhbV90YWJsZV9yaWNobmVzcyA8LSBzYW1fdGFibGVbLGMoJ0NsYXNzJywgJ3JpY2huZXNzJyldCm5hbWVzKHNhbV90YWJsZV9yaWNobmVzcykgPC0gYygnY29uZGl0aW9uJywgJ3JpY2huZXNzJykKYW5pbWFsY3VsZXM6OmFscGhhX2Rpdl90ZXN0KHNhbV90YWJsZSA9IHNhbV90YWJsZV9yaWNobmVzcykKCmFuaW1hbGN1bGVzOjpkaXZlcnNpdHlfYmV0YV9oZWF0bWFwKE1BRSA9IE1BRSwgdGF4X2xldmVsID0gImdlbnVzIiwgaW5wdXRfYmV0YV9tZXRob2QgPSAiYnJheSIsIGlucHV0X2JkaG1fc2VsZWN0X2NvbmRpdGlvbnMgPSAgICJDbGFzcyIsIGlucHV0X2JkaG1fc29ydF9ieSA9ICJjb25kaXRpb25zIikgCgphbmltYWxjdWxlczo6ZGl2ZXJzaXR5X2JldGFfdGVzdChNQUUgPSBNQUUsdGF4X2xldmVsID0gImdlbnVzIiwgaW5wdXRfYmV0YV9tZXRob2QgPSAiYnJheSIsIGlucHV0X3NlbGVjdF9iZXRhX2NvbmRpdGlvbiA9ICJDbGFzcyIsIGlucHV0X3NlbGVjdF9iZXRhX3N0YXRfbWV0aG9kID0gIlBFUk1BTk9WQSIsIGlucHV0X251bV9wZXJtdXRhdGlvbl9wZXJtYW5vdmEgPSAxMDAwKQpgYGAKCmBgYHtyIHdhcm5pbmc9Rn0Kc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKGxpYnJhcnkocGxvdGx5KSkKCmFuaW1hbGN1bGVzOjphbHBoYV9kaXZfYm94cGxvdChNQUUgPSBNQUUsIHRheF9sZXZlbCA9ICJnZW51cyIsIGNvbmRpdGlvbiA9ICJDbGFzcyIsIGFscGhhX21ldHJpYyA9ICJzaGFubm9uIikKYW5pbWFsY3VsZXM6OmFscGhhX2Rpdl9ib3hwbG90KE1BRSA9IE1BRSwgdGF4X2xldmVsID0gInNwZWNpZXMiLCBjb25kaXRpb24gPSAiQ2xhc3MiLCBhbHBoYV9tZXRyaWMgPSAic2hhbm5vbiIpCgphbmltYWxjdWxlczo6ZGl2ZXJzaXR5X2JldGFfaGVhdG1hcChNQUUgPSBNQUUsIHRheF9sZXZlbCA9ICJnZW51cyIsIGlucHV0X2JldGFfbWV0aG9kID0gImJyYXkiLGlucHV0X2JkaG1fc2VsZWN0X2NvbmRpdGlvbnMgPSAgICJDbGFzcyIsIGlucHV0X2JkaG1fc29ydF9ieSA9ICJjb25kaXRpb25zIikKYW5pbWFsY3VsZXM6OmRpdmVyc2l0eV9iZXRhX2hlYXRtYXAoTUFFID0gTUFFLCB0YXhfbGV2ZWwgPSAic3BlY2llcyIsIGlucHV0X2JldGFfbWV0aG9kID0gImJyYXkiLGlucHV0X2JkaG1fc2VsZWN0X2NvbmRpdGlvbnMgPSAgICJDbGFzcyIsIGlucHV0X2JkaG1fc29ydF9ieSA9ICJjb25kaXRpb25zIikKYGBgCgojIyBSZWwgYWJ1IG9mIE1vSSB7LnRhYnNldCAudGFic2V0LWZhZGUgLnRhYnNldC1waWxsc30KCmBgYHtyfQpyMSA8LSByZWxhYnVfYm94cGxvdF93cmFwcGVyKE1BRSA9IE1BRSwgdGF4X2xldmVsID0gImdlbnVzIiwgY29uZGl0aW9uID0gIkNsYXNzIiwgb3JnYW5pc21zID0gYygiRnVzb2JhY3Rlcml1bSIsICJOZWlzc2VyaWEiLCAiUHJldm90ZWxsYSIsICJTaGV3YW5lbGxhIiwgIlN0cmVwdG9jb2NjdXMiLCAiQ2FuZGlkYSIpLCBkYXRhdHlwZSA9ICJsb2djcG0iKQpyMQpgYGAKCgoKIyMgRGlmZi4gRXhwIHsudGFic2V0IC50YWJzZXQtZmFkZSAudGFic2V0LXBpbGxzfQoKYGBge3Igd2FybmluZz1GLCBldmFsPUZ9CmRpZmZhbmFsIDwtIGRpZmZlcmVudGlhbF9hYnVuZGFuY2UoTUFFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGF4X2xldmVsPSJnZW51cyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbnB1dF9kYV9jb25kaXRpb249YygiQ2xhc3MiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlucHV0X2RhX2NvbmRpdGlvbl9jb3ZhcmlhdGUgPSBjKCJTZXgiLCAiaW1wdXRlZF9zbW9raW5nX2xhYmVsIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW5fbnVtX2ZpbHRlciAgPSA1MDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbnB1dF9kYV9wYWRqX2N1dG9mZiA9IDAuMDUsIG1ldGhvZCA9ICdERVNlcTInKQpEVDo6ZGF0YXRhYmxlKGRpZmZhbmFsKQojd3JpdGUueGxzeChkaWZmYW5hbCwgZmlsZT1maWxlLnBhdGgoUEFUSCwgIjA2XzMwX2RpZmZhbmFsX21pY3JvYmVzLnhsc3giKSkKCiNnZXQgbWljcm9iZXMgdW5pcXVlIHRvIGVhY2ggY29udHJhc3QtY29uZGl0aW9uCiN1cCBpbiBmaXJzdCBncm91cCBhbmQgZG93biBpbiB0aGUgb3RoZXIgLSB1cCByZWcKbWljcm9iZV9saXN0IDwtIGxpc3QoImN0cmwudnMuaGtucl91cCI9ZGlmZmFuYWwkbWljcm9iZVt3aGljaChkaWZmYW5hbCRDb250cmFzdD09JzEtQ29udHJvbCB2cy4gMi1Ia05SJyAmIGRpZmZhbmFsJHBhZGogPD0wLjA1ICYgZGlmZmFuYWwkbG9nMkZvbGRDaGFuZ2UgPiAxKV0sCiAgICAgImN0cmwudnMuaGtucl9kb3duIj1kaWZmYW5hbCRtaWNyb2JlW3doaWNoKGRpZmZhbmFsJENvbnRyYXN0PT0nMS1Db250cm9sIHZzLiAyLUhrTlInICYgZGlmZmFuYWwkcGFkaiA8PTAuMDUgJiBkaWZmYW5hbCRsb2cyRm9sZENoYW5nZSA8IC0xKV0sCiAgICAgICJjdHJsLnZzLmR5c191cCI9ZGlmZmFuYWwkbWljcm9iZVt3aGljaChkaWZmYW5hbCRDb250cmFzdD09JzEtQ29udHJvbCB2cy4gMy1EeXNwbGFzaWEnICYgZGlmZmFuYWwkcGFkaiA8PTAuMDUgJiBkaWZmYW5hbCRsb2cyRm9sZENoYW5nZSA+IDEpXSwKICAgICAiY3RybC52cy5keXNfZG93biI9ZGlmZmFuYWwkbWljcm9iZVt3aGljaChkaWZmYW5hbCRDb250cmFzdD09JzEtQ29udHJvbCB2cy4gMy1EeXNwbGFzaWEnICYgZGlmZmFuYWwkcGFkaiA8PTAuMDUgJiBkaWZmYW5hbCRsb2cyRm9sZENoYW5nZSA8IC0xKV0sCiAgICAgImN0cmwudnMuY2FuY2VyX3VwIj1kaWZmYW5hbCRtaWNyb2JlW3doaWNoKGRpZmZhbmFsJENvbnRyYXN0PT0nMS1Db250cm9sIHZzLiA0LUNhbmNlcicgJiBkaWZmYW5hbCRwYWRqIDw9MC4wNSAmIGRpZmZhbmFsJGxvZzJGb2xkQ2hhbmdlID4gMSldLAogICAgICJjdHJsLnZzLmNhbmNlcl9kb3duIj1kaWZmYW5hbCRtaWNyb2JlW3doaWNoKGRpZmZhbmFsJENvbnRyYXN0PT0nMS1Db250cm9sIHZzLiA0LUNhbmNlcicgJiBkaWZmYW5hbCRwYWRqIDw9MC4wNSAmIGRpZmZhbmFsJGxvZzJGb2xkQ2hhbmdlIDwgLTEpXSkKbWljcm9iZV9saXN0Cgojc2F2ZVJEUyhtaWNyb2JlX2xpc3QsIGZpbGUucGF0aCgicmVzdWx0cy8wNl8zMF9taWNyb2JlX2RpZmZleF9saXN0LlJEUyIpKQpgYGAKCgojIyBNU0VBIHsudGFic2V0IC50YWJzZXQtZmFkZSAudGFic2V0LXBpbGxzfQoKTWljcm9iZSBzZXQgZW5yaWNobWVudCBhbmFseXNpcyBbKE1TRUEpXShodHRwczovL3d3dy5uYXR1cmUuY29tL2FydGljbGVzL3M0MTU5OC0wMjAtNzg1MTEteSNTZWMxOCkKTG9hZCByZXN1bHRzIGZyb20gbXNlYSAtIHJhbiBvbiBzY2Mgd2l0aCBhIGp1cHl0ZXIgbm90ZWJvb2sKCiMjIyBPU0NDIHZzLiBDdHJsCgpgYGB7cn0KbXNlYV9jYW5jZXJfdXAgPC0gcmVhZC5jc3YoZmlsZS5wYXRoKFBBVEgsICJyZXN1bHRzL21zZWFfY2FuY2VyX2N0cmxfdXAuY3N2IikpCm1zZWFfY2FuY2VyX2RuIDwtIHJlYWQuY3N2KGZpbGUucGF0aChQQVRILCAicmVzdWx0cy9tc2VhX2NhbmNlcl9jdHJsX2RuLmNzdiIpKQptc2VhX3BtbF91cCA8LSByZWFkLmNzdihmaWxlLnBhdGgoUEFUSCwgInJlc3VsdHMvbXNlYV9wbWxfY3RybF91cC5jc3YiKSkKbXNlYV9wbWxfZG4gPC0gcmVhZC5jc3YoZmlsZS5wYXRoKFBBVEgsICJyZXN1bHRzL21zZWFfcG1sX2N0cmxfZG4uY3N2IikpCgptc2VhX2NhbmNlcl91cCA8LSBtc2VhX2NhbmNlcl91cFttc2VhX2NhbmNlcl91cCRxdmFsdWU8PTAuMDUgJiBtc2VhX2NhbmNlcl91cCRjb21iaW5lZF9zY29yZSA+IDAsXQptc2VhX2NhbmNlcl9kbiA8LSBtc2VhX2NhbmNlcl9kblttc2VhX2NhbmNlcl9kbiRxdmFsdWU8PTAuMDUsXSNub25lIHNpZ25pZmljYW50Cm1zZWFfcG1sX3VwIDwtIG1zZWFfcG1sX3VwW21zZWFfcG1sX3VwJHF2YWx1ZTw9MC4wNSAmIG1zZWFfcG1sX3VwJGNvbWJpbmVkX3Njb3JlID4gMCwgXQptc2VhX3BtbF9kbiA8LSBtc2VhX3BtbF9kblttc2VhX3BtbF9kbiRxdmFsdWU8PTAuMDUsXSNub25lIHNpZ25pZmljYW50Cgptc2VhX2dlbmVzIDwtIGxpc3QoImNhbmNlciIgPSBtc2VhX2NhbmNlcl91cCR0ZXJtLCAKICAgICAgICAgICAgICAgICAgICJwbWwiPW1zZWFfcG1sX3VwJHRlcm0pCgpIQUxMTUFSSyA8LSAgbXNpZ2RiX2dzZXRzKCJIb21vIHNhcGllbnMiLCAiSCIsICIiKQpuYW1lcyhIQUxMTUFSSyRnZW5lc2V0cykgPC0gbmFtZXMoSEFMTE1BUkskZ2VuZXNldHMpICU+JSBzdHJzcGxpdCggIkhBTExNQVJLXyIgKSAlPiUgc2FwcGx5KCB0YWlsLCAxICkKClJFQUNUT01FIDwtIG1zaWdkYl9nc2V0cyhzcGVjaWVzPSJIb21vIHNhcGllbnMiLCBjYXRlZ29yeT0iQzIiLCBzdWJjYXRlZ29yeT0iQ1A6UkVBQ1RPTUUiLCBjbGVhbiA9IFRSVUUpCm5hbWVzKFJFQUNUT01FJGdlbmVzZXRzKSA8LSBuYW1lcyhSRUFDVE9NRSRnZW5lc2V0cykgJT4lIHN0cnNwbGl0KCAiUkVBQ1RPTUVfIiApICU+JSBzYXBwbHkoIHRhaWwsIDEgKQoKCmh5cF9taWMxIDwtIGh5cGVSKHNpZ25hdHVyZSA9IG1zZWFfZ2VuZXMsIGdlbmVzZXRzID0gSEFMTE1BUkssIGJhY2tncm91bmQgPSAxMzAwKQpoeXBfbWljMiA8LSBoeXBlUihzaWduYXR1cmUgPSBtc2VhX2dlbmVzLCBnZW5lc2V0cyA9IEhBTExNQVJLKQpoeXBfZG90cyhoeXBfbWljMSwgbWVyZ2UgPSBULCBmZHIgPSAwLjEsIHRpdGxlID0gIkhhbGxtYXJrKGJjaz0xMzAwKSIpCmh5cF9taWMxJGFzLmxpc3QoKQpoeXBfZG90cyhoeXBfbWljMiwgbWVyZ2UgPSBULCBmZHIgPSAwLjEsIHRpdGxlID0gIkhhbGxtYXJrKGJjaz1hbGwpIikKaHlwX21pYzIkYXMubGlzdCgpCgpoeXBfbWljMyA8LSBoeXBlUihzaWduYXR1cmUgPSBtc2VhX2dlbmVzLCBnZW5lc2V0cyA9IFJFQUNUT01FLCBiYWNrZ3JvdW5kID0gMTMwMCkKaHlwX21pYzQgPC0gaHlwZVIoc2lnbmF0dXJlID0gbXNlYV9nZW5lcywgZ2VuZXNldHMgPSBSRUFDVE9NRSkKaHlwX2RvdHMoaHlwX21pYzMsIG1lcmdlID0gVCwgZmRyID0gMC4xLCB0aXRsZSA9ICJSZWFjdG9tZShiY2s9MTMwMCkiKQpoeXBfbWljMyRhcy5saXN0KCkKaHlwX2RvdHMoaHlwX21pYzQsIG1lcmdlID0gVCwgZmRyID0gMC4xLCB0aXRsZSA9ICJSZWFjdG9tZShiY2s9YWxsKSIpCmh5cF9taWM0JGFzLmxpc3QoKQoKYGBgCgoKIyMjIENhbmNlciBnZW5lcwoKYGBge3J9CmRpZmZhbmFsX3JlcyA8LSB4bHN4OjpyZWFkLnhsc3goZmlsZS5wYXRoKFBBVEgsICJyZXN1bHRzL3BtbF9kaWZmZXhfd29faW5mbC9QTUwuRGlmZkV4LnJlc3VsdHMuQ2FuLnZzLkN0cmwueGxzeCIpLCBzaGVldEluZGV4ID0gMSkKZGlmZmFuYWxfcmVzIDwtIGRpZmZhbmFsX3Jlc1tkaWZmYW5hbF9yZXMkcGFkajw9MC4wNSxdCmRpZmZfY2FuY2VyIDwtIGRpZmZhbmFsX3Jlc1tkaWZmYW5hbF9yZXMkZ2VuZSAlaW4lIG1zZWFfZ2VuZXMkY2FuY2VyLCBdCgpnZ3Bsb3QoZGF0YSA9IGRpZmZfY2FuY2VyLCBhZXMoeD1nZW5lLCB5ID0gbG9nMkZvbGRDaGFuZ2UpLCkrCiAgZ2VvbV9iYXIoYWVzKCBmaWxsPWxvZzJGb2xkQ2hhbmdlPjApLCBzdGF0ID0gImlkZW50aXR5IikrIAogIHRoZW1lX2J3KCkrICAKICBnZ3Bsb3QyOjp0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSsKICBzY2FsZV9maWxsX21hbnVhbChndWlkZSA9ICJub25lIiwgYnJlYWtzID0gYyhUUlVFLCBGQUxTRSksIHZhbHVlcz1jKCJibHVlNCIsICJyZWQiKSkKYGBgCgoKIyMjIENhbmNlciB2cyBDdHJsIHVwCgpgYGB7cn0KbGlicmFyeSh0aWR5dmVyc2UpCm1zZWFfY2FuY2VyX3VwX25ldzwtIHNlcGFyYXRlX3Jvd3MobXNlYV9jYW5jZXJfdXAsIHNoYXJlZCwgc2VwID0gIiwiLCBjb252ZXJ0ID0gVCkKbXNlYV9jYW5jZXJfdXBfbmV3JHNoYXJlZCA8LSBnc3ViKG1zZWFfY2FuY2VyX3VwX25ldyRzaGFyZWQsIHBhdHRlcm4gPSAiXFxbIiwgcmVwbGFjZW1lbnQgPSAiIikKbXNlYV9jYW5jZXJfdXBfbmV3JHNoYXJlZCA8LSBnc3ViKG1zZWFfY2FuY2VyX3VwX25ldyRzaGFyZWQsIHBhdHRlcm4gPSAiXFxdIiwgcmVwbGFjZW1lbnQgPSAiIikKbXNlYV9jYW5jZXJfdXBfbmV3JHNoYXJlZCA8LSBnc3ViKG1zZWFfY2FuY2VyX3VwX25ldyRzaGFyZWQsIHBhdHRlcm4gPSAiXFwnIiwgcmVwbGFjZW1lbnQgPSAiIikKbXNlYV9jYW5jZXJfdXBfbmV3JHNoYXJlZCA8LSBnc3ViKG1zZWFfY2FuY2VyX3VwX25ldyRzaGFyZWQsIHBhdHRlcm4gPSAiICIsIHJlcGxhY2VtZW50ID0gIiIpCm1zZWFfY2FuY2VyX3VwX25ldwoKYGBgCgojIyMgaWdyYXBoCi0gQ2hvb3NlIGdlbmVzIHRoYXQgY29tZSB1cCBkaWZmIGFuYWx5c2lzCi0gdG8gYWRqdXN0IGZvciBkZWdyZWUgc2l6ZSBmb3IgZ2VuZXMgZG91YmxlIGl0CgpgYGB7cn0KbXNlYV9jYW5jZXJfdXBfZGUgPC0gbXNlYV9jYW5jZXJfdXBfbmV3W21zZWFfY2FuY2VyX3VwX25ldyR0ZXJtICVpbiUgZGlmZl9jYW5jZXIkZ2VuZSwgXQpkZiA8LSBtc2VhX2NhbmNlcl91cF9kZVssIGMoInRlcm0iLCAic2hhcmVkIiwgImNvbWJpbmVkX3Njb3JlIildCnRyYW5zZm9ybWVkX21hdCA8LSB4dGFicyhjb21iaW5lZF9zY29yZX4uLCBkZikKYXR0cih0cmFuc2Zvcm1lZF9tYXQsICJjbGFzcyIpIDwtIE5VTEwgI2lnbm9yZSB0aGlzCgojdGRmIDwtIHRhYmxlKG1zZWFfY2FuY2VyX3VwX2RlWywgYygndGVybScsICdzaGFyZWQnKV0pCmcgPC0gZ3JhcGguaW5jaWRlbmNlKHRyYW5zZm9ybWVkX21hdCwgd2VpZ2h0ZWQgPSBUUlVFKQppcy5iaXBhcnRpdGUoZykKZGVnIDwtIGRlZ3JlZShnLCBtb2RlPSJhbGwiKQoKIyBnIDwtIGRlbGV0ZS52ZXJ0aWNlcyhnLCB3aGljaChkZWdyZWUoZyk8NSkpCiMgZGVnIDwtIGRlZ3JlZShnKQoKY29scnMgPC0gYygicmVkIiwiIzZDQTZDRCIpW1YoZykkdHlwZSArIDFMXQoKVihnKSRzaGFwZSA8LSBpZmVsc2UoVihnKSRuYW1lICVpbiUgdW5xdW90ZShtc2VhX2NhbmNlcl91cF9kZSR0ZXJtKSwgImNpcmNsZSIsICJzcXVhcmUiKQpWKGcpJHZlcnRleC5sYWJlbC5kaXN0ID0gMQoKTE8gPSBtYXRyaXgoMCwgbnJvdz12Y291bnQoZyksIG5jb2w9MikKTE9bIVYoZykkdHlwZSwgMl0gPSAxCgpMT1tWKGcpJHR5cGUsIDFdICA9IHJhbmsoVihnKSRuYW1lW1YoZykkdHlwZV0pIC0gMQpMT1shVihnKSR0eXBlLCAxXSA9IChyYW5rKFYoZykkbmFtZVshVihnKSR0eXBlXSkgLSAxKSAqIAogICAgKHN1bShWKGcpJHR5cGUpIC0gMSkgIC8gIChzdW0oIVYoZykkdHlwZSkgLSAxKQoKI2ZvciBhIHZlcnRpY2FsIGJpcGFydGl0ZSBncmFwaApMTyA8LSBMT1ssMjoxXQojTE9bLDJdIDwtIExPWywyXSoyCgpwbG90KGcsIAogICAgIHZlcnRleC5jb2xvciA9IGFkanVzdGNvbG9yKGNvbHJzLCAgYWxwaGEuZiA9IDEpLCAKICAgICB2ZXJ0ZXguZnJhbWUuY29sb3IgPSBjb2xycywKICAgICBsYXlvdXQgPSBMTywgCiAgICAgdmVydGV4LnNpemUgPSBpZmVsc2UoVihnKSRuYW1lICVpbiUgdW5xdW90ZShtc2VhX2NhbmNlcl91cF9kZSR0ZXJtKSwgZGVnKjIuNSwgZGVnKjEuOTUpLAogICAgICN2ZXJ0ZXguc2l6ZSA9IGRlZyozLAogICAgdmVydGV4LmxhYmVsLmRpc3QgPSBpZmVsc2UoVihnKSRuYW1lICVpbiUgdW5xdW90ZShtc2VhX2NhbmNlcl91cF9kZSR0ZXJtKSwgLTgsIDEzKSwKICAgIHZlcnRleC5sYWJlbC5kZWdyZWUgPSAgaWZlbHNlKFYoZykkbmFtZSAlaW4lIHVucXVvdGUobXNlYV9jYW5jZXJfdXBfZGUkdGVybSksIDMuMTQsIC0zLjE0KSwgIyBUaGUgcG9zaXRpb24gb2YgdGhlIGxhYmVsIGluIHJlbGF0aW9uIHRvIHRoZSB2ZXJ0ZXgsIHdoZXJlIDAgaXMgcmlnaHQsIOKAnHBp4oCdIGlzIGxlZnQsIOKAnHBpLzLigJ0gaXMgYmVsb3csIGFuZCDigJwtcGkvMuKAnSBpcyBhYm92ZQogICAgICN2ZXJ0ZXgubGFiZWwuY2V4PTAuNSwKICAgIHZlcnRleC5sYWJlbC5jZXg9IGlmZWxzZShWKGcpJG5hbWUgJWluJSB1bnF1b3RlKG1zZWFfY2FuY2VyX3VwX2RlJHRlcm0pLCAxLCAxKSwKICAgICB2ZXJ0ZXguZnJhbWUud2lkdGg9MC4xLAogICAgIHZlcnRleC5sYWJlbC5jb2xvcj0iYmxhY2siLAogICAgIGVkZ2Uud2lkdGg9YWJzKEUoZykkd2VpZ2h0KS8yMCwgCiAgICAgdmVydGV4LmxhYmVsLmZhbWlseT0iQXJpYWwiLAogICAgdmVydGV4LmxhYmVsLmZvbnQ9aWZlbHNlKFYoZykkbmFtZSAlaW4lIHVucXVvdGUobXNlYV9jYW5jZXJfdXBfZGUkdGVybSksMSwzKSwKICAgICBlZGdlLmNvbG9yID0gImJsYWNrIiwKICAgICBhc3AgPSAyLjUpCmBgYAoKYGBge3IgY2FuY2VyX29sZF9jb2RlLCBldmFsPUZ9Cm1zZWFfY2FuY2VyX3VwX2RlIDwtIG1zZWFfY2FuY2VyX3VwX25ld1ttc2VhX2NhbmNlcl91cF9uZXckdGVybSAlaW4lIGRpZmZfY2FuY2VyJGdlbmUsIF0KZGYgPC0gbXNlYV9jYW5jZXJfdXBfZGVbLCBjKCJ0ZXJtIiwgInNoYXJlZCIsICJjb21iaW5lZF9zY29yZSIpXQp0cmFuc2Zvcm1lZF9tYXQgPC0geHRhYnMoY29tYmluZWRfc2NvcmV+LiwgZGYpCmF0dHIodHJhbnNmb3JtZWRfbWF0LCAiY2xhc3MiKSA8LSBOVUxMICNpZ25vcmUgdGhpcwoKZyA8LSBncmFwaC5pbmNpZGVuY2UodHJhbnNmb3JtZWRfbWF0LCB3ZWlnaHRlZCA9IFRSVUUpCmlzLmJpcGFydGl0ZShnKQpkZWcgPC0gZGVncmVlKGcsIG1vZGU9ImFsbCIpCiNjb2xycyA8LSBjKCIjRkZENTgwIiwiIzZDQTZDRCIpW1YoZykkdHlwZSArIDFMXQoKY29scnMgPC0gYygiIzZDQTZDRCIsICJyZWQiKVtWKGcpJHR5cGUgKyAxTF0KY29scnMgPC0gaWZlbHNlKGNvbHJzPT0icmVkIiAmIFYoZykkbmFtZSAlaW4lIGMoIkNFQUNBTTEiLCAiR0FMRSIsICJJTDE4IiksICJibHVlIiwgY29scnMpCgpWKGcpJHNoYXBlIDwtIGlmZWxzZShWKGcpJG5hbWUgJWluJSB1bnF1b3RlKG1zZWFfY2FuY2VyX3VwX2RlJHRlcm0pLCAiY2lyY2xlIiwgInNxdWFyZSIpCgpMTyA9IG1hdHJpeCgwLCBucm93PXZjb3VudChnKSwgbmNvbD0yKQpMT1shVihnKSR0eXBlLCAyXSA9IDEKCkxPW1YoZykkdHlwZSwgMV0gID0gcmFuayhWKGcpJG5hbWVbVihnKSR0eXBlXSkgLSAxCkxPWyFWKGcpJHR5cGUsIDFdID0gKHJhbmsoVihnKSRuYW1lWyFWKGcpJHR5cGVdKSAtIDEpICogCiAgICAoc3VtKFYoZykkdHlwZSkgLSAxKSAgLyAgKHN1bSghVihnKSR0eXBlKSAtIDEpCgojZm9yIGEgdmVydGljYWwgYmlwYXJ0aXRlIGdyYXBoCkxPIDwtIExPWywyOjFdCgp0aWZmKGZpbGUucGF0aChQQVRILCAicmVzdWx0cy8wNl8xNl9jYW5jZXJfbWljcm9iZXNfaWcucG5nIiksdW5pdHM9ImluIiwgd2lkdGg9NSwgaGVpZ2h0PTUsIHJlcz02MDApCnBsb3QoZywgCiAgICAgdmVydGV4LmNvbG9yID0gYWRqdXN0Y29sb3IoY29scnMsICBhbHBoYS5mID0gMSksIAogICAgIHZlcnRleC5mcmFtZS5jb2xvciA9IGNvbHJzLAogICAgIGxheW91dCA9IExPLCAKICAgICB2ZXJ0ZXguc2l6ZSA9IGlmZWxzZShWKGcpJG5hbWUgJWluJSB1bnF1b3RlKG1zZWFfY2FuY2VyX3VwX2RlJHRlcm0pLCBkZWcqMi41LCBkZWcqMS45NSksCiAgICAgI3ZlcnRleC5zaXplID0gZGVnKjMsCiAgICAgdmVydGV4LmxhYmVsLmRpc3QgPSAtMSwKICAgICB2ZXJ0ZXgubGFiZWwuY2V4PTAuMywKICAgICB2ZXJ0ZXguZnJhbWUud2lkdGg9MC4xLAogICAgIHZlcnRleC5sYWJlbC5jb2xvcj0iYmxhY2siLAogICAgIGVkZ2Uud2lkdGg9YWJzKEUoZykkd2VpZ2h0KS8yMCwgCiAgICAgdmVydGV4LmxhYmVsLmZhbWlseT0iQXJpYWwiLAogICAgIHZlcnRleC5sYWJlbC5mb250PTQsCiAgICAgdmVydGV4LmxhYmVsLmZhY2UgPSAKICAgICBlZGdlLmNvbG9yID0gImJsYWNrIiwKICAgICAjZWRnZS5jb2xvcj1pZmVsc2UoRShnKSR3ZWlnaHQgPiAwLCAicmVkIiwiYmx1ZSIpLAogICAgIGFzcCA9IDIuNSkKZGV2Lm9mZigpCmBgYAoKCmBgYHtyfQptaWNyb2Jlc19jYW5jZXJfc2hhcmVkIDwtIHVuaXF1ZShtc2VhX2NhbmNlcl91cF9kZSRzaGFyZWQpCkRUOjpkYXRhdGFibGUobXNlYV9jYW5jZXJfdXBfZGUpCmBgYAoKCiMjIyBQTUwgdnMuIEN0cmwKCmBgYHtyfQpkaWZmYW5hbF9yZXNfaGtuciA8LSB4bHN4OjpyZWFkLnhsc3goZmlsZS5wYXRoKFBBVEgsICJyZXN1bHRzL3BtbF9kaWZmZXhfd29faW5mbC9QTUwuRGlmZkV4LnJlc3VsdHMuSGtuci52cy5DdHJsLnhsc3giKSwgc2hlZXRJbmRleCA9IDEpCmRpZmZhbmFsX3Jlc19keXMgPC0geGxzeDo6cmVhZC54bHN4KGZpbGUucGF0aChQQVRILCAicmVzdWx0cy9wbWxfZGlmZmV4X3dvX2luZmwvUE1MLkRpZmZFeC5yZXN1bHRzLkR5cy52cy5DdHJsLnhsc3giKSwgc2hlZXRJbmRleCA9IDEpCgpkaWZmYW5hbF9yZXNfaGtuciRnZW5lIDwtIGRpZmZhbmFsX3Jlc19oa25yJE5BLgpkaWZmYW5hbF9yZXNfZHlzJGdlbmUgPC0gZGlmZmFuYWxfcmVzX2R5cyROQS4KCmRpZmZhbmFsX3BtbCA8LSByYmluZChkaWZmYW5hbF9yZXNfZHlzLCBkaWZmYW5hbF9yZXNfaGtucikKCmRpZmZhbmFsX3BtbCA8LSBkaWZmYW5hbF9wbWxbZGlmZmFuYWxfcG1sJHBhZGo8PTAuMDUsXQpkaWZmX3BtbDwtIGRpZmZhbmFsX3BtbFtkaWZmYW5hbF9wbWwkZ2VuZSAlaW4lIG1zZWFfZ2VuZXMkcG1sLCBdCgpnZ3Bsb3QoZGF0YSA9IGRpZmZfcG1sLCBhZXMoeD1nZW5lLCB5ID0gbG9nMkZvbGRDaGFuZ2UpLCkrCiAgZ2VvbV9iYXIoYWVzKCBmaWxsPWxvZzJGb2xkQ2hhbmdlPjApLCBzdGF0ID0gImlkZW50aXR5IikrIAogIHRoZW1lX2J3KCkrICAKICBnZ3Bsb3QyOjp0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSsKICBzY2FsZV9maWxsX21hbnVhbChndWlkZSA9ICJub25lIiwgYnJlYWtzID0gYyhUUlVFLCBGQUxTRSksIHZhbHVlcz1jKCJibHVlNCIsICJyZWQiKSkKYGBgCgojIyMgUE1MIHZzIEN0cmwgdXAKCmBgYHtyfQptc2VhX3BtbF91cF9uZXc8LSBzZXBhcmF0ZV9yb3dzKG1zZWFfcG1sX3VwLCBzaGFyZWQsIHNlcCA9ICIsIiwgY29udmVydCA9IFQpCm1zZWFfcG1sX3VwX25ldyRzaGFyZWQgPC0gZ3N1Yihtc2VhX3BtbF91cF9uZXckc2hhcmVkLCBwYXR0ZXJuID0gIlxcWyIsIHJlcGxhY2VtZW50ID0gIiIpCm1zZWFfcG1sX3VwX25ldyRzaGFyZWQgPC0gZ3N1Yihtc2VhX3BtbF91cF9uZXckc2hhcmVkLCBwYXR0ZXJuID0gIlxcXSIsIHJlcGxhY2VtZW50ID0gIiIpCm1zZWFfcG1sX3VwX25ldyRzaGFyZWQgPC0gZ3N1Yihtc2VhX3BtbF91cF9uZXckc2hhcmVkLCBwYXR0ZXJuID0gIlxcJyIsIHJlcGxhY2VtZW50ID0gIiIpCm1zZWFfcG1sX3VwX25ldyRzaGFyZWQgPC0gZ3N1Yihtc2VhX3BtbF91cF9uZXckc2hhcmVkLCBwYXR0ZXJuID0gIiAiLCByZXBsYWNlbWVudCA9ICIiKQptc2VhX3BtbF91cF9uZXcKCmBgYAoKLSBDaG9vc2UgZ2VuZXMgdGhhdCBjb21lIHVwIGRpZmYgYW5hbHlzaXMKLSB0byBhZGp1c3QgZm9yIGRlZ3JlZSBzaXplIGZvciBnZW5lcyBkb3VibGUgaXQKCgpgYGB7ciBvbGRfY29kZSwgZXZhbD1GfQptc2VhX3BtbF91cF9kZSA8LSBtc2VhX3BtbF91cF9uZXdbbXNlYV9wbWxfdXBfbmV3JHRlcm0gJWluJSBkaWZmX3BtbCRnZW5lLCBdCmRmIDwtIG1zZWFfcG1sX3VwX2RlWywgYygic2hhcmVkIiwgInRlcm0iLCAiY29tYmluZWRfc2NvcmUiKV0KdHJhbnNmb3JtZWRfbWF0IDwtIHh0YWJzKGNvbWJpbmVkX3Njb3Jlfi4sIGRmKQphdHRyKHRyYW5zZm9ybWVkX21hdCwgImNsYXNzIikgPC0gTlVMTCAjaWdub3JlIHRoaXMKCmcgPC0gZ3JhcGguaW5jaWRlbmNlKHRyYW5zZm9ybWVkX21hdCwgd2VpZ2h0ZWQgPSBUUlVFKQppcy5iaXBhcnRpdGUoZykKZGVnIDwtIGRlZ3JlZShnLCBtb2RlPSJhbGwiKQoKY29scnMgPC0gYygiIzdFQzM4NCIsICIjRkZENTgwIilbVihnKSR0eXBlICsgMUxdCgpWKGcpJHNoYXBlIDwtIGlmZWxzZShWKGcpJG5hbWUgJWluJSB1bnF1b3RlKG1zZWFfcG1sX3VwX2RlJHRlcm0pLCAiY2lyY2xlIiwgInNxdWFyZSIpCiNWKGcpJGxhYmVsLmNleiA8LSAxCgpMTyA9IG1hdHJpeCgwLCBucm93PXZjb3VudChnKSwgbmNvbD0yKQpMT1shVihnKSR0eXBlLCAyXSA9IDEKCkxPW1YoZykkdHlwZSwgMV0gID0gcmFuayhWKGcpJG5hbWVbVihnKSR0eXBlXSkgLSAxCkxPWyFWKGcpJHR5cGUsIDFdID0gKHJhbmsoVihnKSRuYW1lWyFWKGcpJHR5cGVdKSAtIDEpICogKHN1bShWKGcpJHR5cGUpIC0gMSkgIC8gIChzdW0oIVYoZykkdHlwZSkgLSAxKQoKI2ZvciBhIHZlcnRpY2FsIGJpcGFydGl0ZSBncmFwaApMTyA8LSBMT1ssMjoxXQojTE9bLDJdIDwtIExPWywyXSoyCgpwbG90KGcsIAogICAgIHZlcnRleC5jb2xvciA9IGFkanVzdGNvbG9yKGNvbHJzLCAgYWxwaGEuZiA9IC42KSwgCiAgICAgdmVydGV4LmZyYW1lLmNvbG9yID0gY29scnMsCiAgICAgbGF5b3V0ID0gTE8sIAogICAgIHZlcnRleC5zaXplID0gaWZlbHNlKFYoZykkbmFtZSAlaW4lIHVucXVvdGUobXNlYV9wbWxfdXBfZGUkdGVybSksIGRlZyoxLjI1LCBkZWcqMS4yNSksCiAgICAgdmVydGV4LmxhYmVsLmRpc3QgPSBpZmVsc2UoVihnKSRuYW1lICVpbiUgdW5xdW90ZShtc2VhX3BtbF91cF9kZSR0ZXJtKSwgMCwgMCksCiAgICAgdmVydGV4LmxhYmVsLmNleD0gaWZlbHNlKFYoZykkbmFtZSAlaW4lIHVucXVvdGUobXNlYV9wbWxfdXBfZGUkdGVybSksIDAuMTgsIDAuMzUpLAogICAgIHZlcnRleC5mcmFtZS53aWR0aD0wLjEsCiAgICAgdmVydGV4LmxhYmVsLmZvbnQ9MywKICAgICBlZGdlLndpZHRoPWFicyhFKGcpJHdlaWdodCkvMjAwLCAKICAgICB2ZXJ0ZXgubGFiZWwuZmFtaWx5PSJBcmlhbCIsCiAgICAgZWRnZS5jb2xvcj1pZmVsc2UoRShnKSR3ZWlnaHQgPiAwLCAicmVkIiwgImJsdWUiKSwgIGFzcCA9IDMpCgpgYGAKCmBgYHtyfQptc2VhX3BtbF91cF9kZSA8LSBtc2VhX3BtbF91cF9uZXdbbXNlYV9wbWxfdXBfbmV3JHRlcm0gJWluJSBkaWZmX3BtbCRnZW5lLCBdCmRmIDwtIG1zZWFfcG1sX3VwX2RlWywgYygic2hhcmVkIiwgInRlcm0iLCAiY29tYmluZWRfc2NvcmUiKV0KdHJhbnNmb3JtZWRfbWF0IDwtIHh0YWJzKGNvbWJpbmVkX3Njb3Jlfi4sIGRmKQphdHRyKHRyYW5zZm9ybWVkX21hdCwgImNsYXNzIikgPC0gTlVMTCAjaWdub3JlIHRoaXMKCiN0ZGYgPC0gdGFibGUobXNlYV9jYW5jZXJfdXBfZGVbLCBjKCd0ZXJtJywgJ3NoYXJlZCcpXSkKZyA8LSBncmFwaC5pbmNpZGVuY2UodHJhbnNmb3JtZWRfbWF0LCB3ZWlnaHRlZCA9IFRSVUUpCmlzLmJpcGFydGl0ZShnKQpkZWcgPC0gZGVncmVlKGcsIG1vZGU9ImFsbCIpCmNvbHJzIDwtIGMoIiM2Q0E2Q0QiLCJyZWQiKVtWKGcpJHR5cGUgKyAxTF0KY29scnMgPC0gaWZlbHNlKGNvbHJzPT0icmVkIiAmIFYoZykkbmFtZSAlaW4lIGMoIkNFQUNBTTEiLCAiR0FMRSIsICJJTDE4IiksICJibHVlIiwgY29scnMpCgpWKGcpJHNoYXBlIDwtIGlmZWxzZShWKGcpJG5hbWUgJWluJSB1bnF1b3RlKG1zZWFfcG1sX3VwX25ldyR0ZXJtKSwgImNpcmNsZSIsICJzcXVhcmUiKQpWKGcpJHZlcnRleC5sYWJlbC5kaXN0ID0gMQoKTE8gPSBtYXRyaXgoMCwgbnJvdz12Y291bnQoZyksIG5jb2w9MikKTE9bIVYoZykkdHlwZSwgMl0gPSAxCgpMT1tWKGcpJHR5cGUsIDFdICA9IHJhbmsoVihnKSRuYW1lW1YoZykkdHlwZV0pIC0gMQpMT1shVihnKSR0eXBlLCAxXSA9IChyYW5rKFYoZykkbmFtZVshVihnKSR0eXBlXSkgLSAxKSAqIAogICAgKHN1bShWKGcpJHR5cGUpIC0gMSkgIC8gIChzdW0oIVYoZykkdHlwZSkgLSAxKQoKI2ZvciBhIHZlcnRpY2FsIGJpcGFydGl0ZSBncmFwaApMTyA8LSBMT1ssMjoxXQoKcGxvdChnLCAKICAgICB2ZXJ0ZXguY29sb3IgPSBhZGp1c3Rjb2xvcihjb2xycywgIGFscGhhLmYgPSAxKSwgCiAgICAgdmVydGV4LmZyYW1lLmNvbG9yID0gY29scnMsCiAgICAgbGF5b3V0ID0gTE8sIAogICAgdmVydGV4LnNpemUgPSBpZmVsc2UoVihnKSRuYW1lICVpbiUgdW5xdW90ZShtc2VhX3BtbF91cF9kZSR0ZXJtKSwgZGVnKjEuNzUsIGRlZyoxLjI1KSwKICAgICB2ZXJ0ZXgubGFiZWwuY2V4PSBpZmVsc2UoVihnKSRuYW1lICVpbiUgdW5xdW90ZShtc2VhX3BtbF91cF9kZSR0ZXJtKSwgMSwxKSwKICAgIHZlcnRleC5sYWJlbC5kaXN0ID0gaWZlbHNlKFYoZykkbmFtZSAlaW4lIHVucXVvdGUobXNlYV9wbWxfdXBfZGUkdGVybSksIDcuNSwgLTEyLjUpLAogICAgdmVydGV4LmxhYmVsLmRlZ3JlZSA9ICBpZmVsc2UoVihnKSRuYW1lICVpbiUgdW5xdW90ZShtc2VhX3BtbF91cF9kZSR0ZXJtKSwgLTMuMTQsLTMuMTQpLCAjIFRoZSBwb3NpdGlvbiBvZiB0aGUgbGFiZWwgaW4gcmVsYXRpb24gdG8gdGhlIHZlcnRleCwgd2hlcmUgMCBpcyByaWdodCwg4oCccGnigJ0gaXMgbGVmdCwg4oCccGkvMuKAnSBpcyBiZWxvdywgYW5kIOKAnC1waS8y4oCdIGlzIGFib3ZlCiAgICAgI3ZlcnRleC5sYWJlbC5jZXg9MC41LAogICAgIHZlcnRleC5mcmFtZS53aWR0aD0wLjEsCiAgICAgdmVydGV4LmxhYmVsLmNvbG9yPSJibGFjayIsCiAgICAgZWRnZS53aWR0aD1hYnMoRShnKSR3ZWlnaHQpLzMwLCAKICAgICB2ZXJ0ZXgubGFiZWwuZmFtaWx5PSJBcmlhbCIsCiAgICAgdmVydGV4LmxhYmVsLmZvbnQ9aWZlbHNlKFYoZykkbmFtZSAlaW4lIHVucXVvdGUobXNlYV9wbWxfdXBfZGUkdGVybSksIDEsMyksCiAgICAgZWRnZS5jb2xvciA9ICJibGFjayIsCiAgICAgYXNwID0gMykKCmBgYAo=